<!doctype html>
<html class="no-js" lang="en" data-content_root="../../">
  <head><meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <meta name="color-scheme" content="light dark"><link rel="index" title="Index" href="../../genindex.html"><link rel="search" title="Search" href="../../search.html">

    <!-- Generated with Sphinx 8.2.3 and Furo 2025.09.25 -->
        <title>osxphotos.export_db - osxphotos 0.74.2 documentation</title>
      <link rel="stylesheet" type="text/css" href="../../_static/pygments.css?v=d111a655" />
    <link rel="stylesheet" type="text/css" href="../../_static/styles/furo.css?v=580074bf" />
    <link rel="stylesheet" type="text/css" href="../../_static/copybutton.css?v=76b2166b" />
    <link rel="stylesheet" type="text/css" href="../../_static/styles/furo-extensions.css?v=8dab3a3b" />
    
    


<style>
  body {
    --color-code-background: #f2f2f2;
  --color-code-foreground: #1e1e1e;
  
  }
  @media not print {
    body[data-theme="dark"] {
      --color-code-background: #202020;
  --color-code-foreground: #d0d0d0;
  
    }
    @media (prefers-color-scheme: dark) {
      body:not([data-theme="light"]) {
        --color-code-background: #202020;
  --color-code-foreground: #d0d0d0;
  
      }
    }
  }
</style></head>
  <body>
    
    <script>
      document.body.dataset.theme = localStorage.getItem("theme") || "auto";
    </script>
    

<svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
  <symbol id="svg-toc" viewBox="0 0 24 24">
    <title>Contents</title>
    <svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 1024 1024">
      <path d="M408 442h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8zm-8 204c0 4.4 3.6 8 8 8h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56zm504-486H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zm0 632H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zM115.4 518.9L271.7 642c5.8 4.6 14.4.5 14.4-6.9V388.9c0-7.4-8.5-11.5-14.4-6.9L115.4 505.1a8.74 8.74 0 0 0 0 13.8z"/>
    </svg>
  </symbol>
  <symbol id="svg-menu" viewBox="0 0 24 24">
    <title>Menu</title>
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor"
      stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather-menu">
      <line x1="3" y1="12" x2="21" y2="12"></line>
      <line x1="3" y1="6" x2="21" y2="6"></line>
      <line x1="3" y1="18" x2="21" y2="18"></line>
    </svg>
  </symbol>
  <symbol id="svg-arrow-right" viewBox="0 0 24 24">
    <title>Expand</title>
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor"
      stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather-chevron-right">
      <polyline points="9 18 15 12 9 6"></polyline>
    </svg>
  </symbol>
  <symbol id="svg-sun" viewBox="0 0 24 24">
    <title>Light mode</title>
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor"
      stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="feather-sun">
      <circle cx="12" cy="12" r="5"></circle>
      <line x1="12" y1="1" x2="12" y2="3"></line>
      <line x1="12" y1="21" x2="12" y2="23"></line>
      <line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line>
      <line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line>
      <line x1="1" y1="12" x2="3" y2="12"></line>
      <line x1="21" y1="12" x2="23" y2="12"></line>
      <line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line>
      <line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line>
    </svg>
  </symbol>
  <symbol id="svg-moon" viewBox="0 0 24 24">
    <title>Dark mode</title>
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor"
      stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="icon-tabler-moon">
      <path stroke="none" d="M0 0h24v24H0z" fill="none" />
      <path d="M12 3c.132 0 .263 0 .393 0a7.5 7.5 0 0 0 7.92 12.446a9 9 0 1 1 -8.313 -12.454z" />
    </svg>
  </symbol>
  <symbol id="svg-sun-with-moon" viewBox="0 0 24 24">
    <title>Auto light/dark, in light mode</title>
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor"
      stroke-width="1" stroke-linecap="round" stroke-linejoin="round"
      class="icon-custom-derived-from-feather-sun-and-tabler-moon">
      <path style="opacity: 50%" d="M 5.411 14.504 C 5.471 14.504 5.532 14.504 5.591 14.504 C 3.639 16.319 4.383 19.569 6.931 20.352 C 7.693 20.586 8.512 20.551 9.25 20.252 C 8.023 23.207 4.056 23.725 2.11 21.184 C 0.166 18.642 1.702 14.949 4.874 14.536 C 5.051 14.512 5.231 14.5 5.411 14.5 L 5.411 14.504 Z"/>
      <line x1="14.5" y1="3.25" x2="14.5" y2="1.25"/>
      <line x1="14.5" y1="15.85" x2="14.5" y2="17.85"/>
      <line x1="10.044" y1="5.094" x2="8.63" y2="3.68"/>
      <line x1="19" y1="14.05" x2="20.414" y2="15.464"/>
      <line x1="8.2" y1="9.55" x2="6.2" y2="9.55"/>
      <line x1="20.8" y1="9.55" x2="22.8" y2="9.55"/>
      <line x1="10.044" y1="14.006" x2="8.63" y2="15.42"/>
      <line x1="19" y1="5.05" x2="20.414" y2="3.636"/>
      <circle cx="14.5" cy="9.55" r="3.6"/>
    </svg>
  </symbol>
  <symbol id="svg-moon-with-sun" viewBox="0 0 24 24">
    <title>Auto light/dark, in dark mode</title>
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor"
      stroke-width="1" stroke-linecap="round" stroke-linejoin="round"
      class="icon-custom-derived-from-feather-sun-and-tabler-moon">
      <path d="M 8.282 7.007 C 8.385 7.007 8.494 7.007 8.595 7.007 C 5.18 10.184 6.481 15.869 10.942 17.24 C 12.275 17.648 13.706 17.589 15 17.066 C 12.851 22.236 5.91 23.143 2.505 18.696 C -0.897 14.249 1.791 7.786 7.342 7.063 C 7.652 7.021 7.965 7 8.282 7 L 8.282 7.007 Z"/>
      <line style="opacity: 50%" x1="18" y1="3.705" x2="18" y2="2.5"/>
      <line style="opacity: 50%" x1="18" y1="11.295" x2="18" y2="12.5"/>
      <line style="opacity: 50%" x1="15.316" y1="4.816" x2="14.464" y2="3.964"/>
      <line style="opacity: 50%" x1="20.711" y1="10.212" x2="21.563" y2="11.063"/>
      <line style="opacity: 50%" x1="14.205" y1="7.5" x2="13.001" y2="7.5"/>
      <line style="opacity: 50%" x1="21.795" y1="7.5" x2="23" y2="7.5"/>
      <line style="opacity: 50%" x1="15.316" y1="10.184" x2="14.464" y2="11.036"/>
      <line style="opacity: 50%" x1="20.711" y1="4.789" x2="21.563" y2="3.937"/>
      <circle style="opacity: 50%" cx="18" cy="7.5" r="2.169"/>
    </svg>
  </symbol>
  <symbol id="svg-pencil" viewBox="0 0 24 24">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor"
      stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="icon-tabler-pencil-code">
      <path d="M4 20h4l10.5 -10.5a2.828 2.828 0 1 0 -4 -4l-10.5 10.5v4" />
      <path d="M13.5 6.5l4 4" />
      <path d="M20 21l2 -2l-2 -2" />
      <path d="M17 17l-2 2l2 2" />
    </svg>
  </symbol>
  <symbol id="svg-eye" viewBox="0 0 24 24">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor"
      stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="icon-tabler-eye-code">
      <path stroke="none" d="M0 0h24v24H0z" fill="none" />
      <path d="M10 12a2 2 0 1 0 4 0a2 2 0 0 0 -4 0" />
      <path
        d="M11.11 17.958c-3.209 -.307 -5.91 -2.293 -8.11 -5.958c2.4 -4 5.4 -6 9 -6c3.6 0 6.6 2 9 6c-.21 .352 -.427 .688 -.647 1.008" />
      <path d="M20 21l2 -2l-2 -2" />
      <path d="M17 17l-2 2l2 2" />
    </svg>
  </symbol>
</svg>

<input type="checkbox" class="sidebar-toggle" name="__navigation" id="__navigation" aria-label="Toggle site navigation sidebar">
<input type="checkbox" class="sidebar-toggle" name="__toc" id="__toc" aria-label="Toggle table of contents sidebar">
<label class="overlay sidebar-overlay" for="__navigation"></label>
<label class="overlay toc-overlay" for="__toc"></label>

<a class="skip-to-content muted-link" href="#furo-main-content">Skip to content</a>



<div class="page">
  <header class="mobile-header">
    <div class="header-left">
      <label class="nav-overlay-icon" for="__navigation">
        <span class="icon"><svg><use href="#svg-menu"></use></svg></span>
      </label>
    </div>
    <div class="header-center">
      <a href="../../index.html"><div class="brand">osxphotos 0.74.2 documentation</div></a>
    </div>
    <div class="header-right">
      <div class="theme-toggle-container theme-toggle-header">
        <button class="theme-toggle" aria-label="Toggle Light / Dark / Auto color theme">
          <svg class="theme-icon-when-auto-light"><use href="#svg-sun-with-moon"></use></svg>
          <svg class="theme-icon-when-auto-dark"><use href="#svg-moon-with-sun"></use></svg>
          <svg class="theme-icon-when-dark"><use href="#svg-moon"></use></svg>
          <svg class="theme-icon-when-light"><use href="#svg-sun"></use></svg>
        </button>
      </div>
      <label class="toc-overlay-icon toc-header-icon no-toc" for="__toc">
        <span class="icon"><svg><use href="#svg-toc"></use></svg></span>
      </label>
    </div>
  </header>
  <aside class="sidebar-drawer">
    <div class="sidebar-container">
      
      <div class="sidebar-sticky"><a class="sidebar-brand" href="../../index.html">
  
  <span class="sidebar-brand-text">osxphotos 0.74.2 documentation</span>
  
</a><form class="sidebar-search-container" method="get" action="../../search.html" role="search">
  <input class="sidebar-search" placeholder="Search" name="q" aria-label="Search">
  <input type="hidden" name="check_keywords" value="yes">
  <input type="hidden" name="area" value="default">
</form>
<div id="searchbox"></div><div class="sidebar-scroll"><div class="sidebar-tree">
  <ul>
<li class="toctree-l1"><a class="reference internal" href="../../overview.html">OSXPhotos</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../tutorial.html">OSXPhotos Tutorial</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../cli.html">OSXPhotos Command Line Interface (CLI)</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../template_help.html">OSXPhotos Template System</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../package_overview.html">OSXPhotos Python Package Overview</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../API_README.html">OSXPhotos Python API</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../reference.html">OSXPhotos Python Reference</a></li>
</ul>

</div>
</div>

      </div>
      
    </div>
  </aside>
  <div class="main">
    <div class="content">
      <div class="article-container">
        <a href="#" class="back-to-top muted-link">
          <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
            <path d="M13 20h-2V8l-5.5 5.5-1.42-1.42L12 4.16l7.92 7.92-1.42 1.42L13 8v12z"></path>
          </svg>
          <span>Back to top</span>
        </a>
        <div class="content-icon-container">
          <div class="theme-toggle-container theme-toggle-content">
            <button class="theme-toggle" aria-label="Toggle Light / Dark / Auto color theme">
              <svg class="theme-icon-when-auto-light"><use href="#svg-sun-with-moon"></use></svg>
              <svg class="theme-icon-when-auto-dark"><use href="#svg-moon-with-sun"></use></svg>
              <svg class="theme-icon-when-dark"><use href="#svg-moon"></use></svg>
              <svg class="theme-icon-when-light"><use href="#svg-sun"></use></svg>
            </button>
          </div>
          <label class="toc-overlay-icon toc-content-icon no-toc" for="__toc">
            <span class="icon"><svg><use href="#svg-toc"></use></svg></span>
          </label>
        </div>
        <article role="main" id="furo-main-content">
          <h1>Source code for osxphotos.export_db</h1><div class="highlight"><pre>
<span></span><span class="sd">&quot;&quot;&quot;Helper class for managing database used by PhotoExporter for tracking state of exports and updates&quot;&quot;&quot;</span>

<span class="kn">from</span><span class="w"> </span><span class="nn">__future__</span><span class="w"> </span><span class="kn">import</span> <span class="n">annotations</span>

<span class="kn">import</span><span class="w"> </span><span class="nn">datetime</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">gzip</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">json</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">logging</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">os</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">os.path</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">pathlib</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">pickle</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">re</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">sqlite3</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">sys</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">threading</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">time</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">contextlib</span><span class="w"> </span><span class="kn">import</span> <span class="n">suppress</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">io</span><span class="w"> </span><span class="kn">import</span> <span class="n">StringIO</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">sqlite3</span><span class="w"> </span><span class="kn">import</span> <span class="n">Error</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">typing</span><span class="w"> </span><span class="kn">import</span> <span class="n">Any</span>

<span class="kn">from</span><span class="w"> </span><span class="nn">tenacity</span><span class="w"> </span><span class="kn">import</span> <span class="n">retry</span><span class="p">,</span> <span class="n">retry_if_not_exception_type</span><span class="p">,</span> <span class="n">stop_after_attempt</span>

<span class="kn">import</span><span class="w"> </span><span class="nn">osxphotos</span>

<span class="kn">from</span><span class="w"> </span><span class="nn">._constants</span><span class="w"> </span><span class="kn">import</span> <span class="n">OSXPHOTOS_EXPORT_DB</span><span class="p">,</span> <span class="n">SQLITE_CHECK_SAME_THREAD</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">._version</span><span class="w"> </span><span class="kn">import</span> <span class="n">__version__</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">.fileutil</span><span class="w"> </span><span class="kn">import</span> <span class="n">FileUtil</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">.sqlite_utils</span><span class="w"> </span><span class="kn">import</span> <span class="p">(</span>
    <span class="n">sqlite_backup_dbfiles</span><span class="p">,</span>
    <span class="n">sqlite_delete_backup_files</span><span class="p">,</span>
    <span class="n">sqlite_delete_dbfiles</span><span class="p">,</span>
<span class="p">)</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">.unicode</span><span class="w"> </span><span class="kn">import</span> <span class="n">normalize_fs_path</span>

<span class="n">__all__</span> <span class="o">=</span> <span class="p">[</span>
    <span class="s2">&quot;ExportDB&quot;</span><span class="p">,</span>
    <span class="s2">&quot;ExportDBInMemory&quot;</span><span class="p">,</span>
    <span class="s2">&quot;ExportDBTemp&quot;</span><span class="p">,</span>
<span class="p">]</span>

<span class="n">OSXPHOTOS_EXPORTDB_VERSION</span> <span class="o">=</span> <span class="s2">&quot;10.1&quot;</span>
<span class="n">OSXPHOTOS_ABOUT_STRING</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">&quot;Created by osxphotos version </span><span class="si">{</span><span class="n">__version__</span><span class="si">}</span><span class="s2"> (https://github.com/RhetTbull/osxphotos) on </span><span class="si">{</span><span class="n">datetime</span><span class="o">.</span><span class="n">datetime</span><span class="o">.</span><span class="n">now</span><span class="p">()</span><span class="si">}</span><span class="s2">&quot;</span>

<span class="c1"># max retry attempts for methods which use tenacity.retry</span>
<span class="n">MAX_RETRY_ATTEMPTS</span> <span class="o">=</span> <span class="mi">3</span>

<span class="c1"># maximum number of export results rows to save</span>
<span class="n">MAX_EXPORT_RESULTS_DATA_ROWS</span> <span class="o">=</span> <span class="mi">10</span>


<span class="n">logger</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">getLogger</span><span class="p">(</span><span class="s2">&quot;osxphotos&quot;</span><span class="p">)</span>


<span class="k">def</span><span class="w"> </span><span class="nf">retry_log_error_no_raise</span><span class="p">(</span><span class="n">retry_state</span><span class="p">):</span>
<span class="w">    </span><span class="sd">&quot;&quot;&quot;Log error for retry but don&#39;t raise exception&quot;&quot;&quot;</span>
    <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span>
        <span class="sa">f</span><span class="s2">&quot;Error </span><span class="si">{</span><span class="n">retry_state</span><span class="o">.</span><span class="n">outcome</span><span class="si">}</span><span class="s2"> for </span><span class="si">{</span><span class="n">retry_state</span><span class="o">.</span><span class="n">fn</span><span class="o">.</span><span class="vm">__name__</span><span class="si">}</span><span class="s2">(</span><span class="si">{</span><span class="n">retry_state</span><span class="o">.</span><span class="n">args</span><span class="si">}</span><span class="s2">, </span><span class="si">{</span><span class="n">retry_state</span><span class="o">.</span><span class="n">kwargs</span><span class="si">}</span><span class="s2">); retrying...&quot;</span><span class="p">,</span>
    <span class="p">)</span>


<span class="k">def</span><span class="w"> </span><span class="nf">pickle_and_zip</span><span class="p">(</span><span class="n">data</span><span class="p">:</span> <span class="n">Any</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">bytes</span><span class="p">:</span>
<span class="w">    </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd">    Pickle and gzip data.</span>

<span class="sd">    Args:</span>
<span class="sd">        data: data to pickle and gzip (must be pickle-able)</span>

<span class="sd">    Returns:</span>
<span class="sd">        bytes of gzipped pickled data</span>
<span class="sd">    &quot;&quot;&quot;</span>
    <span class="n">pickled</span> <span class="o">=</span> <span class="n">pickle</span><span class="o">.</span><span class="n">dumps</span><span class="p">(</span><span class="n">data</span><span class="p">)</span>
    <span class="k">return</span> <span class="n">gzip</span><span class="o">.</span><span class="n">compress</span><span class="p">(</span><span class="n">pickled</span><span class="p">)</span>


<span class="k">def</span><span class="w"> </span><span class="nf">unzip_and_unpickle</span><span class="p">(</span><span class="n">data</span><span class="p">:</span> <span class="nb">bytes</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Any</span><span class="p">:</span>
<span class="w">    </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd">    Unzip and unpickle data.</span>

<span class="sd">    Args:</span>
<span class="sd">        data: data to unzip and unpickle</span>

<span class="sd">    Returns:</span>
<span class="sd">        unpickled data</span>
<span class="sd">    &quot;&quot;&quot;</span>
    <span class="k">return</span> <span class="n">pickle</span><span class="o">.</span><span class="n">loads</span><span class="p">(</span><span class="n">gzip</span><span class="o">.</span><span class="n">decompress</span><span class="p">(</span><span class="n">data</span><span class="p">))</span>


<div class="viewcode-block" id="ExportDB">
<a class="viewcode-back" href="../../reference.html#osxphotos.ExportDB">[docs]</a>
<span class="k">class</span><span class="w"> </span><span class="nc">ExportDB</span><span class="p">:</span>
<span class="w">    </span><span class="sd">&quot;&quot;&quot;Interface to sqlite3 database used to store state information for osxphotos export command</span>

<span class="sd">    Args:</span>
<span class="sd">        dbfile: path to osxphotos export database file</span>
<span class="sd">        export_dir: path to directory where exported files are stored; if None will read value from database</span>
<span class="sd">        version: if supplied, creates database with this version; otherwise uses current version;</span>
<span class="sd">            (must be &gt;= &quot;4.3&quot; and &lt;= OSXPHOTOS_EXPORTDB_VERSION)</span>
<span class="sd">            For testing only; in normal usage, omit this argument</span>

<span class="sd">    Note: export_dir = None must only be used when opening an existing database to read and not to export</span>
<span class="sd">    &quot;&quot;&quot;</span>

    <span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span>
        <span class="bp">self</span><span class="p">,</span>
        <span class="n">dbfile</span><span class="p">:</span> <span class="nb">str</span> <span class="o">|</span> <span class="n">os</span><span class="o">.</span><span class="n">PathLike</span><span class="p">,</span>
        <span class="n">export_dir</span><span class="p">:</span> <span class="nb">str</span> <span class="o">|</span> <span class="n">os</span><span class="o">.</span><span class="n">PathLike</span> <span class="o">|</span> <span class="kc">None</span><span class="p">,</span>
        <span class="n">version</span><span class="p">:</span> <span class="nb">str</span> <span class="o">|</span> <span class="kc">None</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span>
    <span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Create a new ExportDB object</span>

<span class="sd">        Args:</span>
<span class="sd">            dbfile: path to osxphotos export database file</span>
<span class="sd">            export_dir: path to directory where exported files are stored; if None will read value from database</span>
<span class="sd">            version: if supplied, creates database with this version; otherwise uses current version;</span>
<span class="sd">                (must be &gt;= &quot;4.3&quot; and &lt;= OSXPHOTOS_EXPORTDB_VERSION)</span>
<span class="sd">                For testing only; in normal usage, omit this argument</span>

<span class="sd">        Note: export_dir = None must only be used when opening an existing database to read and not to export</span>
<span class="sd">        &quot;&quot;&quot;</span>

        <span class="bp">self</span><span class="o">.</span><span class="n">_dbfile</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="n">dbfile</span><span class="p">)</span>

        <span class="c1"># export_dir allows the database to located in a different path than the export</span>
        <span class="c1"># all paths are stored as relative paths to this path</span>
        <span class="c1"># this allows the entire export tree to be moved to a new disk/location</span>
        <span class="c1"># whilst preserving the UUID to filename mapping</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_path</span><span class="p">:</span> <span class="nb">str</span> <span class="o">|</span> <span class="kc">None</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="n">export_dir</span><span class="p">)</span> <span class="k">if</span> <span class="n">export_dir</span> <span class="k">else</span> <span class="kc">None</span>

        <span class="bp">self</span><span class="o">.</span><span class="n">was_upgraded</span><span class="p">:</span> <span class="nb">tuple</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="nb">str</span><span class="p">]</span> <span class="o">|</span> <span class="nb">tuple</span> <span class="o">=</span> <span class="p">()</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">was_created</span> <span class="o">=</span> <span class="kc">False</span>

        <span class="bp">self</span><span class="o">.</span><span class="n">lock</span> <span class="o">=</span> <span class="n">threading</span><span class="o">.</span><span class="n">Lock</span><span class="p">()</span>

        <span class="bp">self</span><span class="o">.</span><span class="n">_conn</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_open_export_db</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_dbfile</span><span class="p">,</span> <span class="n">version</span><span class="p">)</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_perform_db_maintenance</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_conn</span><span class="p">)</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_insert_run_info</span><span class="p">()</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_insert_export_dir</span><span class="p">()</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">path</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;returns path to export database&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbfile</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">export_dir</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;returns path to export directory&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_path</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">connection</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">sqlite3</span><span class="o">.</span><span class="n">Connection</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;returns sqlite3 connection&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_conn</span> <span class="ow">or</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_db_connection</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_dbfile</span><span class="p">)</span>

<div class="viewcode-block" id="ExportDB.get_file_record">
<a class="viewcode-back" href="../../reference.html#osxphotos.ExportDB.get_file_record">[docs]</a>
    <span class="nd">@retry</span><span class="p">(</span><span class="n">stop</span><span class="o">=</span><span class="n">stop_after_attempt</span><span class="p">(</span><span class="n">MAX_RETRY_ATTEMPTS</span><span class="p">))</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">get_file_record</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">filename</span><span class="p">:</span> <span class="nb">str</span> <span class="o">|</span> <span class="n">os</span><span class="o">.</span><span class="n">PathLike</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="s2">&quot;ExportRecord&quot;</span> <span class="o">|</span> <span class="kc">None</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;get info for filename</span>

<span class="sd">        Returns: an ExportRecord object or None if filename not found</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="n">filename</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_relative_filepath</span><span class="p">(</span><span class="n">filename</span><span class="p">)</span>
        <span class="n">filename_normalized</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_normalize_filepath</span><span class="p">(</span><span class="n">filename</span><span class="p">)</span>

        <span class="k">with</span> <span class="bp">self</span><span class="o">.</span><span class="n">lock</span><span class="p">:</span>
            <span class="n">conn</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">connection</span>
            <span class="n">c</span> <span class="o">=</span> <span class="n">conn</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span>
            <span class="n">result</span> <span class="o">=</span> <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
                <span class="s2">&quot;SELECT uuid FROM export_data WHERE filepath_normalized = ?;&quot;</span><span class="p">,</span>
                <span class="p">(</span><span class="n">filename_normalized</span><span class="p">,),</span>
            <span class="p">)</span><span class="o">.</span><span class="n">fetchone</span><span class="p">()</span>
        <span class="k">return</span> <span class="n">ExportRecord</span><span class="p">(</span><span class="n">conn</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">lock</span><span class="p">,</span> <span class="n">filename_normalized</span><span class="p">)</span> <span class="k">if</span> <span class="n">result</span> <span class="k">else</span> <span class="kc">None</span></div>


<div class="viewcode-block" id="ExportDB.create_file_record">
<a class="viewcode-back" href="../../reference.html#osxphotos.ExportDB.create_file_record">[docs]</a>
    <span class="nd">@retry</span><span class="p">(</span>
        <span class="n">stop</span><span class="o">=</span><span class="n">stop_after_attempt</span><span class="p">(</span><span class="n">MAX_RETRY_ATTEMPTS</span><span class="p">),</span>
        <span class="n">retry</span><span class="o">=</span><span class="n">retry_if_not_exception_type</span><span class="p">(</span><span class="n">sqlite3</span><span class="o">.</span><span class="n">IntegrityError</span><span class="p">),</span>
    <span class="p">)</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">create_file_record</span><span class="p">(</span>
        <span class="bp">self</span><span class="p">,</span> <span class="n">filename</span><span class="p">:</span> <span class="nb">str</span> <span class="o">|</span> <span class="n">os</span><span class="o">.</span><span class="n">PathLike</span><span class="p">,</span> <span class="n">uuid</span><span class="p">:</span> <span class="nb">str</span>
    <span class="p">)</span> <span class="o">-&gt;</span> <span class="s2">&quot;ExportRecord&quot;</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;create a new record for filename and uuid</span>

<span class="sd">        Returns: an ExportRecord object</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="n">filename</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_relative_filepath</span><span class="p">(</span><span class="n">filename</span><span class="p">)</span>
        <span class="n">filename_normalized</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_normalize_filepath</span><span class="p">(</span><span class="n">filename</span><span class="p">)</span>

        <span class="k">with</span> <span class="bp">self</span><span class="o">.</span><span class="n">lock</span><span class="p">:</span>
            <span class="n">conn</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">connection</span>
            <span class="n">c</span> <span class="o">=</span> <span class="n">conn</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span>
            <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
                <span class="s2">&quot;INSERT INTO export_data (filepath, filepath_normalized, uuid) VALUES (?, ?, ?);&quot;</span><span class="p">,</span>
                <span class="p">(</span><span class="n">filename</span><span class="p">,</span> <span class="n">filename_normalized</span><span class="p">,</span> <span class="n">uuid</span><span class="p">),</span>
            <span class="p">)</span>
            <span class="n">conn</span><span class="o">.</span><span class="n">commit</span><span class="p">()</span>
        <span class="k">return</span> <span class="n">ExportRecord</span><span class="p">(</span><span class="n">conn</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">lock</span><span class="p">,</span> <span class="n">filename_normalized</span><span class="p">)</span></div>


<div class="viewcode-block" id="ExportDB.create_or_get_file_record">
<a class="viewcode-back" href="../../reference.html#osxphotos.ExportDB.create_or_get_file_record">[docs]</a>
    <span class="nd">@retry</span><span class="p">(</span>
        <span class="n">stop</span><span class="o">=</span><span class="n">stop_after_attempt</span><span class="p">(</span><span class="n">MAX_RETRY_ATTEMPTS</span><span class="p">),</span>
        <span class="n">retry</span><span class="o">=</span><span class="n">retry_if_not_exception_type</span><span class="p">(</span><span class="n">sqlite3</span><span class="o">.</span><span class="n">IntegrityError</span><span class="p">),</span>
    <span class="p">)</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">create_or_get_file_record</span><span class="p">(</span>
        <span class="bp">self</span><span class="p">,</span> <span class="n">filename</span><span class="p">:</span> <span class="nb">str</span> <span class="o">|</span> <span class="n">os</span><span class="o">.</span><span class="n">PathLike</span><span class="p">,</span> <span class="n">uuid</span><span class="p">:</span> <span class="nb">str</span>
    <span class="p">)</span> <span class="o">-&gt;</span> <span class="s2">&quot;ExportRecord&quot;</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;create a new record for filename and uuid or return existing record</span>

<span class="sd">        Returns: an ExportRecord object</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="n">filename</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_relative_filepath</span><span class="p">(</span><span class="n">filename</span><span class="p">)</span>
        <span class="n">filename_normalized</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_normalize_filepath</span><span class="p">(</span><span class="n">filename</span><span class="p">)</span>

        <span class="k">with</span> <span class="bp">self</span><span class="o">.</span><span class="n">lock</span><span class="p">:</span>
            <span class="n">conn</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">connection</span>
            <span class="n">c</span> <span class="o">=</span> <span class="n">conn</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span>
            <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
                <span class="s2">&quot;INSERT OR IGNORE INTO export_data (filepath, filepath_normalized, uuid) VALUES (?, ?, ?);&quot;</span><span class="p">,</span>
                <span class="p">(</span><span class="n">filename</span><span class="p">,</span> <span class="n">filename_normalized</span><span class="p">,</span> <span class="n">uuid</span><span class="p">),</span>
            <span class="p">)</span>
            <span class="n">conn</span><span class="o">.</span><span class="n">commit</span><span class="p">()</span>
        <span class="k">return</span> <span class="n">ExportRecord</span><span class="p">(</span><span class="n">conn</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">lock</span><span class="p">,</span> <span class="n">filename_normalized</span><span class="p">)</span></div>


<div class="viewcode-block" id="ExportDB.get_uuid_for_file">
<a class="viewcode-back" href="../../reference.html#osxphotos.ExportDB.get_uuid_for_file">[docs]</a>
    <span class="nd">@retry</span><span class="p">(</span><span class="n">stop</span><span class="o">=</span><span class="n">stop_after_attempt</span><span class="p">(</span><span class="n">MAX_RETRY_ATTEMPTS</span><span class="p">))</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">get_uuid_for_file</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">filename</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span> <span class="o">|</span> <span class="kc">None</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;query database for filename and return UUID</span>
<span class="sd">        returns None if filename not found in database</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="n">filepath_normalized</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_normalize_filepath_relative</span><span class="p">(</span><span class="n">filename</span><span class="p">)</span>

        <span class="k">with</span> <span class="bp">self</span><span class="o">.</span><span class="n">lock</span><span class="p">:</span>
            <span class="n">conn</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">connection</span>
            <span class="n">c</span> <span class="o">=</span> <span class="n">conn</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span>
            <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
                <span class="s2">&quot;SELECT uuid FROM export_data WHERE filepath_normalized = ?&quot;</span><span class="p">,</span>
                <span class="p">(</span><span class="n">filepath_normalized</span><span class="p">,),</span>
            <span class="p">)</span>
            <span class="n">results</span> <span class="o">=</span> <span class="n">c</span><span class="o">.</span><span class="n">fetchone</span><span class="p">()</span>
            <span class="k">return</span> <span class="n">results</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="k">if</span> <span class="n">results</span> <span class="k">else</span> <span class="kc">None</span></div>


<div class="viewcode-block" id="ExportDB.get_files_for_uuid">
<a class="viewcode-back" href="../../reference.html#osxphotos.ExportDB.get_files_for_uuid">[docs]</a>
    <span class="nd">@retry</span><span class="p">(</span><span class="n">stop</span><span class="o">=</span><span class="n">stop_after_attempt</span><span class="p">(</span><span class="n">MAX_RETRY_ATTEMPTS</span><span class="p">))</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">get_files_for_uuid</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">uuid</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">list</span><span class="p">[</span><span class="nb">str</span><span class="p">]:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;query database for UUID and return list of files associated with UUID or empty list&quot;&quot;&quot;</span>
        <span class="k">with</span> <span class="bp">self</span><span class="o">.</span><span class="n">lock</span><span class="p">:</span>
            <span class="n">conn</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">connection</span>
            <span class="n">c</span> <span class="o">=</span> <span class="n">conn</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span>
            <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
                <span class="s2">&quot;SELECT filepath FROM export_data WHERE uuid = ?&quot;</span><span class="p">,</span>
                <span class="p">(</span><span class="n">uuid</span><span class="p">,),</span>
            <span class="p">)</span>
            <span class="n">results</span> <span class="o">=</span> <span class="n">c</span><span class="o">.</span><span class="n">fetchall</span><span class="p">()</span>
            <span class="k">return</span> <span class="p">[</span><span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">export_dir</span><span class="p">,</span> <span class="n">r</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span> <span class="k">for</span> <span class="n">r</span> <span class="ow">in</span> <span class="n">results</span><span class="p">]</span></div>


<div class="viewcode-block" id="ExportDB.get_photoinfo_for_uuid">
<a class="viewcode-back" href="../../reference.html#osxphotos.ExportDB.get_photoinfo_for_uuid">[docs]</a>
    <span class="nd">@retry</span><span class="p">(</span><span class="n">stop</span><span class="o">=</span><span class="n">stop_after_attempt</span><span class="p">(</span><span class="n">MAX_RETRY_ATTEMPTS</span><span class="p">))</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">get_photoinfo_for_uuid</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">uuid</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span> <span class="o">|</span> <span class="kc">None</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;returns the photoinfo JSON string for a UUID or None if not found&quot;&quot;&quot;</span>
        <span class="k">with</span> <span class="bp">self</span><span class="o">.</span><span class="n">lock</span><span class="p">:</span>
            <span class="n">conn</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">connection</span>
            <span class="n">c</span> <span class="o">=</span> <span class="n">conn</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span>
            <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s2">&quot;SELECT photoinfo FROM photoinfo WHERE uuid = ?&quot;</span><span class="p">,</span> <span class="p">(</span><span class="n">uuid</span><span class="p">,))</span>
            <span class="n">results</span> <span class="o">=</span> <span class="n">c</span><span class="o">.</span><span class="n">fetchone</span><span class="p">()</span>
            <span class="k">return</span> <span class="n">results</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="k">if</span> <span class="n">results</span> <span class="k">else</span> <span class="kc">None</span></div>


<div class="viewcode-block" id="ExportDB.set_photoinfo_for_uuid">
<a class="viewcode-back" href="../../reference.html#osxphotos.ExportDB.set_photoinfo_for_uuid">[docs]</a>
    <span class="nd">@retry</span><span class="p">(</span>
        <span class="n">stop</span><span class="o">=</span><span class="n">stop_after_attempt</span><span class="p">(</span><span class="n">MAX_RETRY_ATTEMPTS</span><span class="p">),</span>
        <span class="n">retry</span><span class="o">=</span><span class="n">retry_if_not_exception_type</span><span class="p">(</span><span class="n">sqlite3</span><span class="o">.</span><span class="n">IntegrityError</span><span class="p">),</span>
    <span class="p">)</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">set_photoinfo_for_uuid</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">uuid</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">info</span><span class="p">:</span> <span class="nb">str</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;sets the photoinfo JSON string for a UUID&quot;&quot;&quot;</span>
        <span class="k">with</span> <span class="bp">self</span><span class="o">.</span><span class="n">lock</span><span class="p">:</span>
            <span class="n">conn</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">connection</span>
            <span class="n">c</span> <span class="o">=</span> <span class="n">conn</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span>
            <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
                <span class="s2">&quot;INSERT OR REPLACE INTO photoinfo(uuid, photoinfo) VALUES (?, ?);&quot;</span><span class="p">,</span>
                <span class="p">(</span><span class="n">uuid</span><span class="p">,</span> <span class="n">info</span><span class="p">),</span>
            <span class="p">)</span>
            <span class="n">conn</span><span class="o">.</span><span class="n">commit</span><span class="p">()</span></div>


<div class="viewcode-block" id="ExportDB.get_target_for_file">
<a class="viewcode-back" href="../../reference.html#osxphotos.ExportDB.get_target_for_file">[docs]</a>
    <span class="nd">@retry</span><span class="p">(</span><span class="n">stop</span><span class="o">=</span><span class="n">stop_after_attempt</span><span class="p">(</span><span class="n">MAX_RETRY_ATTEMPTS</span><span class="p">))</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">get_target_for_file</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">uuid</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">filename</span><span class="p">:</span> <span class="nb">str</span> <span class="o">|</span> <span class="n">os</span><span class="o">.</span><span class="n">PathLike</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span> <span class="o">|</span> <span class="kc">None</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;query database for file matching file name and return the matching filename if there is one;</span>
<span class="sd">           otherwise return None; looks for file.ext, file (1).ext, file (2).ext and so on to find the</span>
<span class="sd">           actual target name that was used to export filename</span>

<span class="sd">        Returns: the matching filename or None if no match found</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="k">with</span> <span class="bp">self</span><span class="o">.</span><span class="n">lock</span><span class="p">:</span>
            <span class="n">conn</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">connection</span>
            <span class="n">c</span> <span class="o">=</span> <span class="n">conn</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span>
            <span class="n">filepath_normalized</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_normalize_filepath_relative</span><span class="p">(</span><span class="n">filename</span><span class="p">)</span>
            <span class="n">filepath_stem</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">splitext</span><span class="p">(</span><span class="n">filepath_normalized</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span>
            <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
                <span class="s2">&quot;SELECT uuid, filepath, filepath_normalized FROM export_data WHERE uuid = ? AND filepath_normalized LIKE ?&quot;</span><span class="p">,</span>
                <span class="p">(</span>
                    <span class="n">uuid</span><span class="p">,</span>
                    <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">filepath_stem</span><span class="si">}</span><span class="s2">%&quot;</span><span class="p">,</span>
                <span class="p">),</span>
            <span class="p">)</span>
            <span class="n">results</span> <span class="o">=</span> <span class="n">c</span><span class="o">.</span><span class="n">fetchall</span><span class="p">()</span>

            <span class="k">for</span> <span class="n">result</span> <span class="ow">in</span> <span class="n">results</span><span class="p">:</span>
                <span class="n">filepath_normalized</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">splitext</span><span class="p">(</span><span class="n">result</span><span class="p">[</span><span class="mi">2</span><span class="p">])[</span><span class="mi">0</span><span class="p">]</span>
                <span class="k">if</span> <span class="n">re</span><span class="o">.</span><span class="n">match</span><span class="p">(</span>
                    <span class="n">re</span><span class="o">.</span><span class="n">escape</span><span class="p">(</span><span class="n">filepath_stem</span><span class="p">)</span> <span class="o">+</span> <span class="sa">r</span><span class="s2">&quot;(\s\(\d+\))?$&quot;</span><span class="p">,</span> <span class="n">filepath_normalized</span>
                <span class="p">):</span>
                    <span class="k">return</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">export_dir</span><span class="p">,</span> <span class="n">result</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span>

            <span class="k">return</span> <span class="kc">None</span></div>


<div class="viewcode-block" id="ExportDB.get_previous_uuids">
<a class="viewcode-back" href="../../reference.html#osxphotos.ExportDB.get_previous_uuids">[docs]</a>
    <span class="nd">@retry</span><span class="p">(</span><span class="n">stop</span><span class="o">=</span><span class="n">stop_after_attempt</span><span class="p">(</span><span class="n">MAX_RETRY_ATTEMPTS</span><span class="p">))</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">get_previous_uuids</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;returns list of UUIDs of previously exported photos found in export database&quot;&quot;&quot;</span>
        <span class="k">with</span> <span class="bp">self</span><span class="o">.</span><span class="n">lock</span><span class="p">:</span>
            <span class="n">conn</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">connection</span>
            <span class="n">c</span> <span class="o">=</span> <span class="n">conn</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span>
            <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s2">&quot;SELECT DISTINCT uuid FROM export_data&quot;</span><span class="p">)</span>
            <span class="n">results</span> <span class="o">=</span> <span class="n">c</span><span class="o">.</span><span class="n">fetchall</span><span class="p">()</span>
            <span class="k">return</span> <span class="p">[</span><span class="n">row</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="k">for</span> <span class="n">row</span> <span class="ow">in</span> <span class="n">results</span><span class="p">]</span></div>


<div class="viewcode-block" id="ExportDB.set_config">
<a class="viewcode-back" href="../../reference.html#osxphotos.ExportDB.set_config">[docs]</a>
    <span class="nd">@retry</span><span class="p">(</span>
        <span class="n">stop</span><span class="o">=</span><span class="n">stop_after_attempt</span><span class="p">(</span><span class="n">MAX_RETRY_ATTEMPTS</span><span class="p">),</span>
        <span class="n">retry</span><span class="o">=</span><span class="n">retry_if_not_exception_type</span><span class="p">(</span><span class="n">sqlite3</span><span class="o">.</span><span class="n">IntegrityError</span><span class="p">),</span>
    <span class="p">)</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">set_config</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">config_data</span><span class="p">:</span> <span class="nb">str</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;set config in the database&quot;&quot;&quot;</span>
        <span class="k">with</span> <span class="bp">self</span><span class="o">.</span><span class="n">lock</span><span class="p">:</span>
            <span class="n">conn</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">connection</span>
            <span class="n">dt</span> <span class="o">=</span> <span class="n">datetime</span><span class="o">.</span><span class="n">datetime</span><span class="o">.</span><span class="n">now</span><span class="p">()</span><span class="o">.</span><span class="n">isoformat</span><span class="p">()</span>
            <span class="n">c</span> <span class="o">=</span> <span class="n">conn</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span>
            <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
                <span class="s2">&quot;INSERT OR REPLACE INTO config(datetime, config) VALUES (?, ?);&quot;</span><span class="p">,</span>
                <span class="p">(</span><span class="n">dt</span><span class="p">,</span> <span class="n">config_data</span><span class="p">),</span>
            <span class="p">)</span>
            <span class="n">conn</span><span class="o">.</span><span class="n">commit</span><span class="p">()</span></div>


<div class="viewcode-block" id="ExportDB.set_export_results">
<a class="viewcode-back" href="../../reference.html#osxphotos.ExportDB.set_export_results">[docs]</a>
    <span class="nd">@retry</span><span class="p">(</span>
        <span class="n">stop</span><span class="o">=</span><span class="n">stop_after_attempt</span><span class="p">(</span><span class="n">MAX_RETRY_ATTEMPTS</span><span class="p">),</span>
        <span class="n">retry</span><span class="o">=</span><span class="n">retry_if_not_exception_type</span><span class="p">(</span><span class="n">sqlite3</span><span class="o">.</span><span class="n">IntegrityError</span><span class="p">),</span>
    <span class="p">)</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">set_export_results</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">results</span><span class="p">:</span> <span class="s2">&quot;osxphotos.photoexporter.ExportResults&quot;</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Store export results in database; data is pickled and gzipped for storage&quot;&quot;&quot;</span>

        <span class="n">results_data</span> <span class="o">=</span> <span class="n">pickle_and_zip</span><span class="p">(</span><span class="n">results</span><span class="p">)</span>

        <span class="k">with</span> <span class="bp">self</span><span class="o">.</span><span class="n">lock</span><span class="p">:</span>
            <span class="n">conn</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">connection</span>
            <span class="n">dt</span> <span class="o">=</span> <span class="n">datetime</span><span class="o">.</span><span class="n">datetime</span><span class="o">.</span><span class="n">now</span><span class="p">()</span><span class="o">.</span><span class="n">isoformat</span><span class="p">()</span>
            <span class="n">c</span> <span class="o">=</span> <span class="n">conn</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span>
            <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
<span class="w">                </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd">                UPDATE export_results_data</span>
<span class="sd">                SET datetime = ?,</span>
<span class="sd">                    export_results = ?</span>
<span class="sd">                WHERE datetime = (SELECT MIN(datetime) FROM export_results_data);</span>
<span class="sd">                &quot;&quot;&quot;</span><span class="p">,</span>
                <span class="p">(</span><span class="n">dt</span><span class="p">,</span> <span class="n">results_data</span><span class="p">),</span>
            <span class="p">)</span>
            <span class="n">conn</span><span class="o">.</span><span class="n">commit</span><span class="p">()</span></div>


<div class="viewcode-block" id="ExportDB.get_export_results">
<a class="viewcode-back" href="../../reference.html#osxphotos.ExportDB.get_export_results">[docs]</a>
    <span class="nd">@retry</span><span class="p">(</span><span class="n">stop</span><span class="o">=</span><span class="n">stop_after_attempt</span><span class="p">(</span><span class="n">MAX_RETRY_ATTEMPTS</span><span class="p">))</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">get_export_results</span><span class="p">(</span>
        <span class="bp">self</span><span class="p">,</span> <span class="n">run</span><span class="p">:</span> <span class="nb">int</span> <span class="o">=</span> <span class="mi">0</span>
    <span class="p">)</span> <span class="o">-&gt;</span> <span class="s2">&quot;osxphotos.photoexporter.ExportResults&quot;</span> <span class="o">|</span> <span class="kc">None</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Retrieve export results from database</span>

<span class="sd">        Args:</span>
<span class="sd">            run: which run to retrieve results for;</span>
<span class="sd">            0 = most recent run, -1 = previous run, -2 = run prior to that, etc.</span>

<span class="sd">        Returns:</span>
<span class="sd">            ExportResults object or None if no results found</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="k">if</span> <span class="n">run</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">:</span>
            <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s2">&quot;run must be 0 or negative&quot;</span><span class="p">)</span>
        <span class="n">run</span> <span class="o">=</span> <span class="o">-</span><span class="n">run</span>

        <span class="k">with</span> <span class="bp">self</span><span class="o">.</span><span class="n">lock</span><span class="p">:</span>
            <span class="n">conn</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">connection</span>
            <span class="n">c</span> <span class="o">=</span> <span class="n">conn</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span>
            <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
<span class="w">                </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd">                SELECT export_results</span>
<span class="sd">                FROM export_results_data</span>
<span class="sd">                ORDER BY datetime DESC</span>
<span class="sd">                &quot;&quot;&quot;</span><span class="p">,</span>
            <span class="p">)</span>
            <span class="n">rows</span> <span class="o">=</span> <span class="n">c</span><span class="o">.</span><span class="n">fetchall</span><span class="p">()</span>
            <span class="k">try</span><span class="p">:</span>
                <span class="n">data</span> <span class="o">=</span> <span class="n">rows</span><span class="p">[</span><span class="n">run</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span>
                <span class="n">results</span> <span class="o">=</span> <span class="n">unzip_and_unpickle</span><span class="p">(</span><span class="n">data</span><span class="p">)</span> <span class="k">if</span> <span class="n">data</span> <span class="k">else</span> <span class="kc">None</span>
            <span class="k">except</span> <span class="ne">IndexError</span><span class="p">:</span>
                <span class="n">results</span> <span class="o">=</span> <span class="kc">None</span>
            <span class="k">return</span> <span class="n">results</span></div>


<div class="viewcode-block" id="ExportDB.get_exported_files">
<a class="viewcode-back" href="../../reference.html#osxphotos.ExportDB.get_exported_files">[docs]</a>
    <span class="nd">@retry</span><span class="p">(</span><span class="n">stop</span><span class="o">=</span><span class="n">stop_after_attempt</span><span class="p">(</span><span class="n">MAX_RETRY_ATTEMPTS</span><span class="p">))</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">get_exported_files</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Returns tuple of (uuid, filepath) for all paths of all exported files tracked in the database&quot;&quot;&quot;</span>
        <span class="k">with</span> <span class="bp">self</span><span class="o">.</span><span class="n">lock</span><span class="p">:</span>
            <span class="n">conn</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">connection</span>
            <span class="n">c</span> <span class="o">=</span> <span class="n">conn</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span>
            <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s2">&quot;SELECT uuid, filepath FROM export_data&quot;</span><span class="p">)</span>

            <span class="k">while</span> <span class="n">row</span> <span class="o">:=</span> <span class="n">c</span><span class="o">.</span><span class="n">fetchone</span><span class="p">():</span>
                <span class="k">yield</span> <span class="n">row</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">export_dir</span><span class="p">,</span> <span class="n">row</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span>
            <span class="k">return</span></div>


<div class="viewcode-block" id="ExportDB.delete_data_for_uuid">
<a class="viewcode-back" href="../../reference.html#osxphotos.ExportDB.delete_data_for_uuid">[docs]</a>
    <span class="nd">@retry</span><span class="p">(</span><span class="n">stop</span><span class="o">=</span><span class="n">stop_after_attempt</span><span class="p">(</span><span class="n">MAX_RETRY_ATTEMPTS</span><span class="p">))</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">delete_data_for_uuid</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">uuid</span><span class="p">:</span> <span class="nb">str</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Delete all exportdb data for given UUID&quot;&quot;&quot;</span>
        <span class="k">with</span> <span class="bp">self</span><span class="o">.</span><span class="n">lock</span><span class="p">:</span>
            <span class="n">conn</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">connection</span>
            <span class="n">c</span> <span class="o">=</span> <span class="n">conn</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span>
            <span class="n">count</span> <span class="o">=</span> <span class="mi">0</span>
            <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s2">&quot;DELETE FROM export_data WHERE uuid = ?;&quot;</span><span class="p">,</span> <span class="p">(</span><span class="n">uuid</span><span class="p">,))</span>
            <span class="n">count</span> <span class="o">+=</span> <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s2">&quot;SELECT CHANGES();&quot;</span><span class="p">)</span><span class="o">.</span><span class="n">fetchone</span><span class="p">()[</span><span class="mi">0</span><span class="p">]</span>
            <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s2">&quot;DELETE FROM photoinfo WHERE uuid = ?;&quot;</span><span class="p">,</span> <span class="p">(</span><span class="n">uuid</span><span class="p">,))</span>
            <span class="n">count</span> <span class="o">+=</span> <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s2">&quot;SELECT CHANGES();&quot;</span><span class="p">)</span><span class="o">.</span><span class="n">fetchone</span><span class="p">()[</span><span class="mi">0</span><span class="p">]</span>
            <span class="n">conn</span><span class="o">.</span><span class="n">commit</span><span class="p">()</span>
            <span class="k">return</span> <span class="n">count</span></div>


<div class="viewcode-block" id="ExportDB.delete_data_for_filepath">
<a class="viewcode-back" href="../../reference.html#osxphotos.ExportDB.delete_data_for_filepath">[docs]</a>
    <span class="nd">@retry</span><span class="p">(</span><span class="n">stop</span><span class="o">=</span><span class="n">stop_after_attempt</span><span class="p">(</span><span class="n">MAX_RETRY_ATTEMPTS</span><span class="p">))</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">delete_data_for_filepath</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">filepath</span><span class="p">:</span> <span class="nb">str</span> <span class="o">|</span> <span class="n">os</span><span class="o">.</span><span class="n">PathLike</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Delete all exportdb data for given filepath&quot;&quot;&quot;</span>
        <span class="k">with</span> <span class="bp">self</span><span class="o">.</span><span class="n">lock</span><span class="p">:</span>
            <span class="n">conn</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">connection</span>
            <span class="n">c</span> <span class="o">=</span> <span class="n">conn</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span>
            <span class="n">filepath_normalized</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_normalize_filepath_relative</span><span class="p">(</span><span class="n">filepath</span><span class="p">)</span>
            <span class="n">results</span> <span class="o">=</span> <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
                <span class="s2">&quot;SELECT uuid FROM export_data WHERE filepath_normalized = ?;&quot;</span><span class="p">,</span>
                <span class="p">(</span><span class="n">filepath_normalized</span><span class="p">,),</span>
            <span class="p">)</span><span class="o">.</span><span class="n">fetchall</span><span class="p">()</span>
        <span class="k">return</span> <span class="nb">sum</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">delete_data_for_uuid</span><span class="p">(</span><span class="n">row</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span> <span class="k">for</span> <span class="n">row</span> <span class="ow">in</span> <span class="n">results</span><span class="p">)</span></div>


    <span class="c1"># @retry(stop=stop_after_attempt(MAX_RETRY_ATTEMPTS))</span>
<div class="viewcode-block" id="ExportDB.set_history">
<a class="viewcode-back" href="../../reference.html#osxphotos.ExportDB.set_history">[docs]</a>
    <span class="k">def</span><span class="w"> </span><span class="nf">set_history</span><span class="p">(</span>
        <span class="bp">self</span><span class="p">,</span>
        <span class="n">filename</span><span class="p">:</span> <span class="nb">str</span> <span class="o">|</span> <span class="n">os</span><span class="o">.</span><span class="n">PathLike</span><span class="p">,</span>
        <span class="n">uuid</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span>
        <span class="n">action</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span>
        <span class="n">diff</span><span class="p">:</span> <span class="nb">str</span> <span class="o">|</span> <span class="kc">None</span><span class="p">,</span>
    <span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Set the history record for the filepath</span>

<span class="sd">        Args:</span>
<span class="sd">            filename: path to file</span>
<span class="sd">            action: action taken on file, e.g. &quot;exported&quot;, &quot;skipped&quot;, &quot;missing&quot;, &quot;updated&quot;</span>
<span class="sd">            diff: diff for file as a serialized JSON str</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="n">filename_normalized</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_normalize_filepath_relative</span><span class="p">(</span><span class="n">filename</span><span class="p">)</span>
        <span class="k">with</span> <span class="bp">self</span><span class="o">.</span><span class="n">lock</span><span class="p">:</span>
            <span class="n">conn</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">connection</span>
            <span class="n">c</span> <span class="o">=</span> <span class="n">conn</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span>
            <span class="k">if</span> <span class="n">filepath_id</span> <span class="o">:=</span> <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
                <span class="s2">&quot;SELECT id FROM history_path WHERE filepath_normalized = ?;&quot;</span><span class="p">,</span>
                <span class="p">(</span><span class="n">filename_normalized</span><span class="p">,),</span>
            <span class="p">)</span><span class="o">.</span><span class="n">fetchone</span><span class="p">():</span>
                <span class="n">filepath_id</span> <span class="o">=</span> <span class="n">filepath_id</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
            <span class="k">else</span><span class="p">:</span>
                <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
                    <span class="s2">&quot;INSERT INTO history_path (filepath_normalized, uuid) VALUES (?, ?);&quot;</span><span class="p">,</span>
                    <span class="p">(</span><span class="n">filename_normalized</span><span class="p">,</span> <span class="n">uuid</span><span class="p">),</span>
                <span class="p">)</span>
                <span class="n">filepath_id</span> <span class="o">=</span> <span class="n">c</span><span class="o">.</span><span class="n">lastrowid</span>
            <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
                <span class="s2">&quot;INSERT INTO history (filepath_id, action, diff) VALUES (?, ?, ?);&quot;</span><span class="p">,</span>
                <span class="p">(</span><span class="n">filepath_id</span><span class="p">,</span> <span class="n">action</span><span class="p">,</span> <span class="n">diff</span><span class="p">),</span>
            <span class="p">)</span>
            <span class="n">conn</span><span class="o">.</span><span class="n">commit</span><span class="p">()</span></div>


    <span class="c1"># @retry(stop=stop_after_attempt(MAX_RETRY_ATTEMPTS))</span>
<div class="viewcode-block" id="ExportDB.get_history">
<a class="viewcode-back" href="../../reference.html#osxphotos.ExportDB.get_history">[docs]</a>
    <span class="k">def</span><span class="w"> </span><span class="nf">get_history</span><span class="p">(</span>
        <span class="bp">self</span><span class="p">,</span> <span class="n">filepath</span><span class="p">:</span> <span class="nb">str</span> <span class="o">|</span> <span class="n">os</span><span class="o">.</span><span class="n">PathLike</span> <span class="o">|</span> <span class="kc">None</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span> <span class="n">uuid</span><span class="p">:</span> <span class="nb">str</span> <span class="o">|</span> <span class="kc">None</span> <span class="o">=</span> <span class="kc">None</span>
    <span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Get history for a filepath or uuid</span>

<span class="sd">        Args:</span>
<span class="sd">            filepath: path to file</span>
<span class="sd">            uuid: UUID of file</span>

<span class="sd">        Returns:</span>
<span class="sd">            list of history records</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="k">with</span> <span class="bp">self</span><span class="o">.</span><span class="n">lock</span><span class="p">:</span>
            <span class="n">conn</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">connection</span>
            <span class="n">c</span> <span class="o">=</span> <span class="n">conn</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span>
            <span class="k">if</span> <span class="n">filepath</span><span class="p">:</span>
                <span class="n">filepath_normalized</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_normalize_filepath_relative</span><span class="p">(</span><span class="n">filepath</span><span class="p">)</span>
                <span class="n">results</span> <span class="o">=</span> <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
<span class="w">                    </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd">                    SELECT datetime, action, diff</span>
<span class="sd">                    FROM history_path</span>
<span class="sd">                    JOIN history ON history_path.id = history.filepath_id</span>
<span class="sd">                    WHERE filepath_normalized = ?</span>
<span class="sd">                    ORDER BY datetime ASC</span>
<span class="sd">                    &quot;&quot;&quot;</span><span class="p">,</span>
                    <span class="p">(</span><span class="n">filepath_normalized</span><span class="p">,),</span>
                <span class="p">)</span><span class="o">.</span><span class="n">fetchall</span><span class="p">()</span>
            <span class="k">elif</span> <span class="n">uuid</span><span class="p">:</span>
                <span class="n">results</span> <span class="o">=</span> <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
<span class="w">                    </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd">                    SELECT datetime, action, diff</span>
<span class="sd">                    FROM history_path</span>
<span class="sd">                    JOIN history ON history_path.id = history.filepath_id</span>
<span class="sd">                    WHERE uuid = ?</span>
<span class="sd">                    ORDER BY datetime ASC</span>
<span class="sd">                    &quot;&quot;&quot;</span><span class="p">,</span>
                    <span class="p">(</span><span class="n">uuid</span><span class="p">,),</span>
                <span class="p">)</span><span class="o">.</span><span class="n">fetchall</span><span class="p">()</span>
            <span class="k">else</span><span class="p">:</span>
                <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s2">&quot;Must specify filepath or uuid&quot;</span><span class="p">)</span>
            <span class="k">return</span> <span class="n">results</span></div>


    <span class="c1"># @retry(stop=stop_after_attempt(MAX_RETRY_ATTEMPTS))</span>
<div class="viewcode-block" id="ExportDB.get_last_export_directory">
<a class="viewcode-back" href="../../reference.html#osxphotos.ExportDB.get_last_export_directory">[docs]</a>
    <span class="k">def</span><span class="w"> </span><span class="nf">get_last_export_directory</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span> <span class="o">|</span> <span class="kc">None</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return the last export directory from the database&quot;&quot;&quot;</span>
        <span class="k">with</span> <span class="bp">self</span><span class="o">.</span><span class="n">lock</span><span class="p">:</span>
            <span class="n">conn</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">connection</span>
            <span class="n">c</span> <span class="o">=</span> <span class="n">conn</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span>
            <span class="n">results</span> <span class="o">=</span> <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
<span class="w">                </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd">                SELECT export_directory</span>
<span class="sd">                FROM export_directory</span>
<span class="sd">                ORDER BY id DESC</span>
<span class="sd">                LIMIT 1;</span>
<span class="sd">                &quot;&quot;&quot;</span>
            <span class="p">)</span><span class="o">.</span><span class="n">fetchone</span><span class="p">()</span>
            <span class="k">if</span> <span class="ow">not</span> <span class="n">results</span><span class="p">:</span>
                <span class="k">return</span> <span class="kc">None</span>
            <span class="k">return</span> <span class="n">results</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span></div>


<div class="viewcode-block" id="ExportDB.close">
<a class="viewcode-back" href="../../reference.html#osxphotos.ExportDB.close">[docs]</a>
    <span class="nd">@retry</span><span class="p">(</span><span class="n">stop</span><span class="o">=</span><span class="n">stop_after_attempt</span><span class="p">(</span><span class="n">MAX_RETRY_ATTEMPTS</span><span class="p">))</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">close</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;close the database connection&quot;&quot;&quot;</span>
        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_conn</span><span class="p">:</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_conn</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_conn</span> <span class="o">=</span> <span class="kc">None</span></div>


    <span class="k">def</span><span class="w"> </span><span class="nf">_open_export_db</span><span class="p">(</span>
        <span class="bp">self</span><span class="p">,</span> <span class="n">dbfile</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">version</span><span class="p">:</span> <span class="nb">str</span> <span class="o">|</span> <span class="kc">None</span> <span class="o">=</span> <span class="kc">None</span>
    <span class="p">)</span> <span class="o">-&gt;</span> <span class="n">sqlite3</span><span class="o">.</span><span class="n">Connection</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;open export database and return a db connection</span>
<span class="sd">        if dbfile does not exist, will create and initialize the database</span>
<span class="sd">        if dbfile needs to be upgraded, will perform needed migrations</span>
<span class="sd">        returns: connection to the database</span>
<span class="sd">        &quot;&quot;&quot;</span>

        <span class="k">if</span> <span class="ow">not</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">isfile</span><span class="p">(</span><span class="n">dbfile</span><span class="p">):</span>
            <span class="n">conn</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_db_connection</span><span class="p">(</span><span class="n">dbfile</span><span class="p">)</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_create_or_migrate_db_tables</span><span class="p">(</span><span class="n">conn</span><span class="p">,</span> <span class="n">version</span><span class="o">=</span><span class="n">version</span><span class="p">)</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">was_created</span> <span class="o">=</span> <span class="kc">True</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">was_upgraded</span> <span class="o">=</span> <span class="p">()</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">version</span> <span class="o">=</span> <span class="n">version</span> <span class="ow">or</span> <span class="n">OSXPHOTOS_EXPORTDB_VERSION</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="n">conn</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_db_connection</span><span class="p">(</span><span class="n">dbfile</span><span class="p">)</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">was_created</span> <span class="o">=</span> <span class="kc">False</span>
            <span class="n">version_info</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_database_version</span><span class="p">(</span><span class="n">conn</span><span class="p">)</span>
            <span class="k">if</span> <span class="nb">float</span><span class="p">(</span><span class="n">version_info</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span> <span class="o">&lt;</span> <span class="nb">float</span><span class="p">(</span><span class="n">OSXPHOTOS_EXPORTDB_VERSION</span><span class="p">):</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_create_or_migrate_db_tables</span><span class="p">(</span><span class="n">conn</span><span class="p">)</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">was_upgraded</span> <span class="o">=</span> <span class="p">(</span><span class="n">version_info</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">OSXPHOTOS_EXPORTDB_VERSION</span><span class="p">)</span>
            <span class="k">else</span><span class="p">:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">was_upgraded</span> <span class="o">=</span> <span class="p">()</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">version</span> <span class="o">=</span> <span class="n">OSXPHOTOS_EXPORTDB_VERSION</span>

        <span class="c1"># turn on performance optimizations</span>
        <span class="k">with</span> <span class="bp">self</span><span class="o">.</span><span class="n">lock</span><span class="p">:</span>
            <span class="n">c</span> <span class="o">=</span> <span class="n">conn</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span>
            <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s2">&quot;PRAGMA journal_mode=WAL;&quot;</span><span class="p">)</span>
            <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s2">&quot;PRAGMA synchronous=NORMAL;&quot;</span><span class="p">)</span>
            <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s2">&quot;PRAGMA cache_size=-100000;&quot;</span><span class="p">)</span>
            <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s2">&quot;PRAGMA temp_store=MEMORY;&quot;</span><span class="p">)</span>

        <span class="k">return</span> <span class="n">conn</span>

    <span class="nd">@retry</span><span class="p">(</span><span class="n">stop</span><span class="o">=</span><span class="n">stop_after_attempt</span><span class="p">(</span><span class="n">MAX_RETRY_ATTEMPTS</span><span class="p">))</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">_get_db_connection</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">dbfile</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">sqlite3</span><span class="o">.</span><span class="n">Connection</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;return db connection to dbname&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="n">sqlite3</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">dbfile</span><span class="p">,</span> <span class="n">check_same_thread</span><span class="o">=</span><span class="n">SQLITE_CHECK_SAME_THREAD</span><span class="p">)</span>

    <span class="nd">@retry</span><span class="p">(</span><span class="n">stop</span><span class="o">=</span><span class="n">stop_after_attempt</span><span class="p">(</span><span class="n">MAX_RETRY_ATTEMPTS</span><span class="p">))</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">_get_database_version</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">conn</span><span class="p">:</span> <span class="n">sqlite3</span><span class="o">.</span><span class="n">Connection</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">tuple</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="nb">str</span><span class="p">]:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;return tuple of (osxphotos, exportdb) versions for database connection conn&quot;&quot;&quot;</span>
        <span class="k">with</span> <span class="bp">self</span><span class="o">.</span><span class="n">lock</span><span class="p">:</span>
            <span class="n">version_info</span> <span class="o">=</span> <span class="n">conn</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
                <span class="s2">&quot;SELECT osxphotos, exportdb, max(id) FROM version&quot;</span>
            <span class="p">)</span><span class="o">.</span><span class="n">fetchone</span><span class="p">()</span>
            <span class="n">version</span> <span class="o">=</span> <span class="p">(</span><span class="n">version_info</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">version_info</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span>
            <span class="k">if</span> <span class="ow">not</span> <span class="n">version</span><span class="p">[</span><span class="mi">1</span><span class="p">]:</span>
                <span class="c1"># database may have not been initialized, #1435</span>
                <span class="n">version</span> <span class="o">=</span> <span class="p">(</span><span class="n">version</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="s2">&quot;4.3&quot;</span><span class="p">)</span>
            <span class="k">return</span> <span class="n">version</span>

    <span class="k">def</span><span class="w"> </span><span class="nf">_create_or_migrate_db_tables</span><span class="p">(</span>
        <span class="bp">self</span><span class="p">,</span> <span class="n">conn</span><span class="p">:</span> <span class="n">sqlite3</span><span class="o">.</span><span class="n">Connection</span><span class="p">,</span> <span class="n">version</span><span class="p">:</span> <span class="nb">str</span> <span class="o">|</span> <span class="kc">None</span> <span class="o">=</span> <span class="kc">None</span>
    <span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;create (if not already created) the necessary db tables for the export database and apply any needed migrations</span>

<span class="sd">        Args:</span>
<span class="sd">            conn: sqlite3 db connection</span>
<span class="sd">            version: if supplied, creates database with this version; otherwise uses current version;</span>
<span class="sd">                (must be &gt;= &quot;4.3&quot; and &lt;= OSXPHOTOS_EXPORTDB_VERSION)</span>
<span class="sd">                For testing only; in normal usage, omit this argument</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="k">try</span><span class="p">:</span>
            <span class="n">version_info</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_database_version</span><span class="p">(</span><span class="n">conn</span><span class="p">)</span>
        <span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
            <span class="n">version_info</span> <span class="o">=</span> <span class="p">(</span><span class="n">__version__</span><span class="p">,</span> <span class="s2">&quot;4.3&quot;</span><span class="p">)</span>

        <span class="n">max_version</span> <span class="o">=</span> <span class="nb">float</span><span class="p">(</span><span class="n">OSXPHOTOS_EXPORTDB_VERSION</span><span class="p">)</span>
        <span class="n">version</span> <span class="o">=</span> <span class="nb">float</span><span class="p">(</span><span class="n">version</span><span class="p">)</span> <span class="k">if</span> <span class="n">version</span> <span class="k">else</span> <span class="n">max_version</span>
        <span class="n">current_version</span> <span class="o">=</span> <span class="nb">float</span><span class="p">(</span><span class="n">version_info</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span>
        <span class="k">if</span> <span class="n">version</span> <span class="o">&lt;</span> <span class="nb">float</span><span class="p">(</span><span class="s2">&quot;4.3&quot;</span><span class="p">):</span>
            <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span>
                <span class="sa">f</span><span class="s2">&quot;Requested database version </span><span class="si">{</span><span class="n">version</span><span class="si">}</span><span class="s2"> is older than minimum supported version 4.3&quot;</span>
            <span class="p">)</span>
        <span class="k">if</span> <span class="n">version</span> <span class="o">&gt;</span> <span class="n">max_version</span><span class="p">:</span>
            <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span>
                <span class="sa">f</span><span class="s2">&quot;Requested database version </span><span class="si">{</span><span class="n">version</span><span class="si">}</span><span class="s2"> is newer than maximum supported version </span><span class="si">{</span><span class="n">OSXPHOTOS_EXPORTDB_VERSION</span><span class="si">}</span><span class="s2">&quot;</span>
            <span class="p">)</span>
        <span class="k">if</span> <span class="n">current_version</span> <span class="o">&gt;</span> <span class="n">version</span><span class="p">:</span>
            <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span>
                <span class="sa">f</span><span class="s2">&quot;Database version </span><span class="si">{</span><span class="n">version_info</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span><span class="si">}</span><span class="s2"> is newer than requested version </span><span class="si">{</span><span class="n">version</span><span class="si">}</span><span class="s2">&quot;</span>
            <span class="p">)</span>

        <span class="c1"># Current for version 4.3, for anything greater, do a migration after creation</span>
        <span class="n">sql_commands</span> <span class="o">=</span> <span class="p">[</span>
<span class="w">            </span><span class="sd">&quot;&quot;&quot; CREATE TABLE IF NOT EXISTS version (</span>
<span class="sd">                    id INTEGER PRIMARY KEY,</span>
<span class="sd">                    osxphotos TEXT,</span>
<span class="sd">                    exportdb TEXT</span>
<span class="sd">                    ); &quot;&quot;&quot;</span><span class="p">,</span>
<span class="w">            </span><span class="sd">&quot;&quot;&quot; CREATE TABLE IF NOT EXISTS about (</span>
<span class="sd">                    id INTEGER PRIMARY KEY,</span>
<span class="sd">                    about TEXT</span>
<span class="sd">                    );&quot;&quot;&quot;</span><span class="p">,</span>
<span class="w">            </span><span class="sd">&quot;&quot;&quot; CREATE TABLE IF NOT EXISTS files (</span>
<span class="sd">                    id INTEGER PRIMARY KEY,</span>
<span class="sd">                    filepath TEXT NOT NULL,</span>
<span class="sd">                    filepath_normalized TEXT NOT NULL,</span>
<span class="sd">                    uuid TEXT,</span>
<span class="sd">                    orig_mode INTEGER,</span>
<span class="sd">                    orig_size INTEGER,</span>
<span class="sd">                    orig_mtime REAL,</span>
<span class="sd">                    exif_mode INTEGER,</span>
<span class="sd">                    exif_size INTEGER,</span>
<span class="sd">                    exif_mtime REAL</span>
<span class="sd">                    ); &quot;&quot;&quot;</span><span class="p">,</span>
<span class="w">            </span><span class="sd">&quot;&quot;&quot; CREATE TABLE IF NOT EXISTS runs (</span>
<span class="sd">                    id INTEGER PRIMARY KEY,</span>
<span class="sd">                    datetime TEXT,</span>
<span class="sd">                    python_path TEXT,</span>
<span class="sd">                    script_name TEXT,</span>
<span class="sd">                    args TEXT,</span>
<span class="sd">                    cwd TEXT</span>
<span class="sd">                    ); &quot;&quot;&quot;</span><span class="p">,</span>
<span class="w">            </span><span class="sd">&quot;&quot;&quot; CREATE TABLE IF NOT EXISTS info (</span>
<span class="sd">                    id INTEGER PRIMARY KEY,</span>
<span class="sd">                    uuid text NOT NULL,</span>
<span class="sd">                    json_info JSON</span>
<span class="sd">                    ); &quot;&quot;&quot;</span><span class="p">,</span>
<span class="w">            </span><span class="sd">&quot;&quot;&quot; CREATE TABLE IF NOT EXISTS exifdata (</span>
<span class="sd">                    id INTEGER PRIMARY KEY,</span>
<span class="sd">                    filepath_normalized TEXT NOT NULL,</span>
<span class="sd">                    json_exifdata JSON</span>
<span class="sd">                    ); &quot;&quot;&quot;</span><span class="p">,</span>
<span class="w">            </span><span class="sd">&quot;&quot;&quot; CREATE TABLE IF NOT EXISTS edited (</span>
<span class="sd">                    id INTEGER PRIMARY KEY,</span>
<span class="sd">                    filepath_normalized TEXT NOT NULL,</span>
<span class="sd">                    mode INTEGER,</span>
<span class="sd">                    size INTEGER,</span>
<span class="sd">                    mtime REAL</span>
<span class="sd">                    ); &quot;&quot;&quot;</span><span class="p">,</span>
<span class="w">            </span><span class="sd">&quot;&quot;&quot; CREATE TABLE IF NOT EXISTS converted (</span>
<span class="sd">                    id INTEGER PRIMARY KEY,</span>
<span class="sd">                    filepath_normalized TEXT NOT NULL,</span>
<span class="sd">                    mode INTEGER,</span>
<span class="sd">                    size INTEGER,</span>
<span class="sd">                    mtime REAL</span>
<span class="sd">                    ); &quot;&quot;&quot;</span><span class="p">,</span>
<span class="w">            </span><span class="sd">&quot;&quot;&quot; CREATE TABLE IF NOT EXISTS sidecar (</span>
<span class="sd">                    id INTEGER PRIMARY KEY,</span>
<span class="sd">                    filepath_normalized TEXT NOT NULL,</span>
<span class="sd">                    sidecar_data TEXT,</span>
<span class="sd">                    mode INTEGER,</span>
<span class="sd">                    size INTEGER,</span>
<span class="sd">                    mtime REAL</span>
<span class="sd">                    ); &quot;&quot;&quot;</span><span class="p">,</span>
<span class="w">            </span><span class="sd">&quot;&quot;&quot; CREATE TABLE IF NOT EXISTS detected_text (</span>
<span class="sd">                    id INTEGER PRIMARY KEY,</span>
<span class="sd">                    uuid TEXT NOT NULL,</span>
<span class="sd">                    text_data JSON</span>
<span class="sd">                    ); &quot;&quot;&quot;</span><span class="p">,</span>
<span class="w">            </span><span class="sd">&quot;&quot;&quot; CREATE UNIQUE INDEX IF NOT EXISTS idx_files_filepath_normalized on files (filepath_normalized); &quot;&quot;&quot;</span><span class="p">,</span>
<span class="w">            </span><span class="sd">&quot;&quot;&quot; CREATE UNIQUE INDEX IF NOT EXISTS idx_info_uuid on info (uuid); &quot;&quot;&quot;</span><span class="p">,</span>
<span class="w">            </span><span class="sd">&quot;&quot;&quot; CREATE UNIQUE INDEX IF NOT EXISTS idx_exifdata_filename on exifdata (filepath_normalized); &quot;&quot;&quot;</span><span class="p">,</span>
<span class="w">            </span><span class="sd">&quot;&quot;&quot; CREATE UNIQUE INDEX IF NOT EXISTS idx_edited_filename on edited (filepath_normalized);&quot;&quot;&quot;</span><span class="p">,</span>
<span class="w">            </span><span class="sd">&quot;&quot;&quot; CREATE UNIQUE INDEX IF NOT EXISTS idx_converted_filename on converted (filepath_normalized);&quot;&quot;&quot;</span><span class="p">,</span>
<span class="w">            </span><span class="sd">&quot;&quot;&quot; CREATE UNIQUE INDEX IF NOT EXISTS idx_sidecar_filename on sidecar (filepath_normalized);&quot;&quot;&quot;</span><span class="p">,</span>
<span class="w">            </span><span class="sd">&quot;&quot;&quot; CREATE UNIQUE INDEX IF NOT EXISTS idx_detected_text on detected_text (uuid);&quot;&quot;&quot;</span><span class="p">,</span>
        <span class="p">]</span>

        <span class="c1"># create the tables if needed</span>
        <span class="k">with</span> <span class="bp">self</span><span class="o">.</span><span class="n">lock</span><span class="p">:</span>
            <span class="n">c</span> <span class="o">=</span> <span class="n">conn</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span>
            <span class="k">for</span> <span class="n">cmd</span> <span class="ow">in</span> <span class="n">sql_commands</span><span class="p">:</span>
                <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="n">cmd</span><span class="p">)</span>
            <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
                <span class="s2">&quot;INSERT INTO version(osxphotos, exportdb) VALUES (?, ?);&quot;</span><span class="p">,</span>
                <span class="p">(</span><span class="n">__version__</span><span class="p">,</span> <span class="n">version</span><span class="p">),</span>
            <span class="p">)</span>
            <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s2">&quot;INSERT INTO about(about) VALUES (?);&quot;</span><span class="p">,</span> <span class="p">(</span><span class="n">OSXPHOTOS_ABOUT_STRING</span><span class="p">,))</span>
            <span class="n">conn</span><span class="o">.</span><span class="n">commit</span><span class="p">()</span>

        <span class="c1"># perform needed migrations</span>
        <span class="c1"># compare float(str) to avoid any issues with comparing float(str) to float</span>
        <span class="k">if</span> <span class="n">current_version</span> <span class="o">&lt;</span> <span class="nb">float</span><span class="p">(</span><span class="s2">&quot;4.3&quot;</span><span class="p">):</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_migrate_normalized_filepath</span><span class="p">(</span><span class="n">conn</span><span class="p">)</span>

        <span class="k">if</span> <span class="n">current_version</span> <span class="o">&lt;</span> <span class="nb">float</span><span class="p">(</span><span class="s2">&quot;5.0&quot;</span><span class="p">)</span> <span class="ow">and</span> <span class="n">version</span> <span class="o">&gt;=</span> <span class="nb">float</span><span class="p">(</span><span class="s2">&quot;5.0&quot;</span><span class="p">):</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_migrate_4_3_to_5_0</span><span class="p">(</span><span class="n">conn</span><span class="p">)</span>

        <span class="k">if</span> <span class="n">current_version</span> <span class="o">&lt;</span> <span class="nb">float</span><span class="p">(</span><span class="s2">&quot;6.0&quot;</span><span class="p">)</span> <span class="ow">and</span> <span class="n">version</span> <span class="o">&gt;=</span> <span class="nb">float</span><span class="p">(</span><span class="s2">&quot;6.0&quot;</span><span class="p">):</span>
            <span class="c1"># create export_data table</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_migrate_5_0_to_6_0</span><span class="p">(</span><span class="n">conn</span><span class="p">)</span>

        <span class="k">if</span> <span class="n">current_version</span> <span class="o">&lt;</span> <span class="nb">float</span><span class="p">(</span><span class="s2">&quot;7.0&quot;</span><span class="p">)</span> <span class="ow">and</span> <span class="n">version</span> <span class="o">&gt;=</span> <span class="nb">float</span><span class="p">(</span><span class="s2">&quot;7.0&quot;</span><span class="p">):</span>
            <span class="c1"># create report_data table</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_migrate_6_0_to_7_0</span><span class="p">(</span><span class="n">conn</span><span class="p">)</span>

        <span class="k">if</span> <span class="n">current_version</span> <span class="o">&lt;</span> <span class="nb">float</span><span class="p">(</span><span class="s2">&quot;7.1&quot;</span><span class="p">)</span> <span class="ow">and</span> <span class="n">version</span> <span class="o">&gt;=</span> <span class="nb">float</span><span class="p">(</span><span class="s2">&quot;7.1&quot;</span><span class="p">):</span>
            <span class="c1"># add timestamp to export_data</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_migrate_7_0_to_7_1</span><span class="p">(</span><span class="n">conn</span><span class="p">)</span>

        <span class="k">if</span> <span class="n">current_version</span> <span class="o">&lt;</span> <span class="nb">float</span><span class="p">(</span><span class="s2">&quot;8.0&quot;</span><span class="p">)</span> <span class="ow">and</span> <span class="n">version</span> <span class="o">&gt;=</span> <span class="nb">float</span><span class="p">(</span><span class="s2">&quot;8.0&quot;</span><span class="p">):</span>
            <span class="c1"># add error to export_data</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_migrate_7_1_to_8_0</span><span class="p">(</span><span class="n">conn</span><span class="p">)</span>

        <span class="k">if</span> <span class="n">current_version</span> <span class="o">&lt;</span> <span class="nb">float</span><span class="p">(</span><span class="s2">&quot;9.0&quot;</span><span class="p">)</span> <span class="ow">and</span> <span class="n">version</span> <span class="o">&gt;=</span> <span class="nb">float</span><span class="p">(</span><span class="s2">&quot;9.0&quot;</span><span class="p">):</span>
            <span class="c1"># add history table</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_migrate_8_0_to_9_0</span><span class="p">(</span><span class="n">conn</span><span class="p">)</span>

        <span class="k">if</span> <span class="n">current_version</span> <span class="o">&lt;</span> <span class="nb">float</span><span class="p">(</span><span class="s2">&quot;9.1&quot;</span><span class="p">)</span> <span class="ow">and</span> <span class="n">version</span> <span class="o">&gt;=</span> <span class="nb">float</span><span class="p">(</span><span class="s2">&quot;9.1&quot;</span><span class="p">):</span>
            <span class="c1"># Add history index</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_migrate_9_0_to_9_1</span><span class="p">(</span><span class="n">conn</span><span class="p">)</span>

        <span class="k">if</span> <span class="n">current_version</span> <span class="o">&lt;</span> <span class="nb">float</span><span class="p">(</span><span class="s2">&quot;10.0&quot;</span><span class="p">)</span> <span class="ow">and</span> <span class="n">version</span> <span class="o">&gt;=</span> <span class="nb">float</span><span class="p">(</span><span class="s2">&quot;10.0&quot;</span><span class="p">):</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_migrate_9_1_to_10_0</span><span class="p">(</span><span class="n">conn</span><span class="p">)</span>

        <span class="k">if</span> <span class="n">current_version</span> <span class="o">&lt;</span> <span class="nb">float</span><span class="p">(</span><span class="s2">&quot;10.1&quot;</span><span class="p">)</span> <span class="ow">and</span> <span class="n">version</span> <span class="o">&gt;=</span> <span class="nb">float</span><span class="p">(</span><span class="s2">&quot;10.1&quot;</span><span class="p">):</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_migrate_10_0_to_10_1</span><span class="p">(</span><span class="n">conn</span><span class="p">)</span>

        <span class="k">with</span> <span class="bp">self</span><span class="o">.</span><span class="n">lock</span><span class="p">:</span>
            <span class="n">conn</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s2">&quot;VACUUM;&quot;</span><span class="p">)</span>
            <span class="n">conn</span><span class="o">.</span><span class="n">commit</span><span class="p">()</span>

    <span class="k">def</span><span class="w"> </span><span class="fm">__del__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;ensure the database connection is closed&quot;&quot;&quot;</span>
        <span class="k">with</span> <span class="n">suppress</span><span class="p">(</span><span class="ne">Exception</span><span class="p">):</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_conn</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>

    <span class="nd">@retry</span><span class="p">(</span><span class="n">stop</span><span class="o">=</span><span class="n">stop_after_attempt</span><span class="p">(</span><span class="n">MAX_RETRY_ATTEMPTS</span><span class="p">))</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">_insert_run_info</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Insert run info into runs table&quot;&quot;&quot;</span>
        <span class="n">dt</span> <span class="o">=</span> <span class="n">datetime</span><span class="o">.</span><span class="n">datetime</span><span class="o">.</span><span class="n">now</span><span class="p">(</span><span class="n">datetime</span><span class="o">.</span><span class="n">timezone</span><span class="o">.</span><span class="n">utc</span><span class="p">)</span><span class="o">.</span><span class="n">isoformat</span><span class="p">()</span>
        <span class="n">python_path</span> <span class="o">=</span> <span class="n">sys</span><span class="o">.</span><span class="n">executable</span>
        <span class="n">cmd</span> <span class="o">=</span> <span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
        <span class="n">args</span> <span class="o">=</span> <span class="s2">&quot; &quot;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">:])</span> <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">1</span> <span class="k">else</span> <span class="s2">&quot;&quot;</span>
        <span class="n">cwd</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">getcwd</span><span class="p">()</span>
        <span class="k">with</span> <span class="bp">self</span><span class="o">.</span><span class="n">lock</span><span class="p">:</span>
            <span class="n">conn</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">connection</span>
            <span class="n">c</span> <span class="o">=</span> <span class="n">conn</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span>
            <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
                <span class="s2">&quot;INSERT INTO runs (datetime, python_path, script_name, args, cwd) VALUES (?, ?, ?, ?, ?)&quot;</span><span class="p">,</span>
                <span class="p">(</span><span class="n">dt</span><span class="p">,</span> <span class="n">python_path</span><span class="p">,</span> <span class="n">cmd</span><span class="p">,</span> <span class="n">args</span><span class="p">,</span> <span class="n">cwd</span><span class="p">),</span>
            <span class="p">)</span>
            <span class="n">conn</span><span class="o">.</span><span class="n">commit</span><span class="p">()</span>

    <span class="nd">@retry</span><span class="p">(</span><span class="n">stop</span><span class="o">=</span><span class="n">stop_after_attempt</span><span class="p">(</span><span class="n">MAX_RETRY_ATTEMPTS</span><span class="p">))</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">_insert_export_dir</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Insert export_directory info into export_directory table&quot;&quot;&quot;</span>

        <span class="k">if</span> <span class="nb">float</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">version</span><span class="p">)</span> <span class="o">&lt;</span> <span class="nb">float</span><span class="p">(</span><span class="s2">&quot;10.0&quot;</span><span class="p">):</span>
            <span class="k">return</span>

        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_path</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
            <span class="c1"># database opened without a path specified, do not update</span>
            <span class="k">return</span>

        <span class="k">with</span> <span class="bp">self</span><span class="o">.</span><span class="n">lock</span><span class="p">:</span>
            <span class="n">conn</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">connection</span>
            <span class="n">c</span> <span class="o">=</span> <span class="n">conn</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span>
            <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
<span class="w">                </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd">                INSERT INTO export_directory (export_directory)</span>
<span class="sd">                SELECT ?</span>
<span class="sd">                WHERE ? &lt;&gt; (</span>
<span class="sd">                    SELECT export_directory</span>
<span class="sd">                    FROM export_directory</span>
<span class="sd">                    ORDER BY rowid DESC</span>
<span class="sd">                    LIMIT 1</span>
<span class="sd">                ) OR NOT EXISTS (</span>
<span class="sd">                    SELECT 1 FROM export_directory</span>
<span class="sd">                )</span>
<span class="sd">            &quot;&quot;&quot;</span><span class="p">,</span>
                <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_path</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">_path</span><span class="p">),</span>
            <span class="p">)</span>

            <span class="n">conn</span><span class="o">.</span><span class="n">commit</span><span class="p">()</span>

    <span class="k">def</span><span class="w"> </span><span class="nf">_relative_filepath</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">filepath</span><span class="p">:</span> <span class="nb">str</span> <span class="o">|</span> <span class="n">os</span><span class="o">.</span><span class="n">PathLike</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;return filepath relative to self.export_dir&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="nb">str</span><span class="p">(</span><span class="n">pathlib</span><span class="o">.</span><span class="n">Path</span><span class="p">(</span><span class="n">filepath</span><span class="p">)</span><span class="o">.</span><span class="n">relative_to</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">export_dir</span><span class="p">))</span>

    <span class="k">def</span><span class="w"> </span><span class="nf">_normalize_filepath</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">filepath</span><span class="p">:</span> <span class="nb">str</span> <span class="o">|</span> <span class="n">os</span><span class="o">.</span><span class="n">PathLike</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;normalize filepath for unicode, lower case&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="n">normalize_fs_path</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="n">filepath</span><span class="p">))</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span>

    <span class="k">def</span><span class="w"> </span><span class="nf">_normalize_filepath_relative</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">filepath</span><span class="p">:</span> <span class="nb">str</span> <span class="o">|</span> <span class="n">os</span><span class="o">.</span><span class="n">PathLike</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;normalize filepath for unicode, relative path (to export dir), lower case&quot;&quot;&quot;</span>
        <span class="n">filepath</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_relative_filepath</span><span class="p">(</span><span class="n">filepath</span><span class="p">)</span>
        <span class="k">return</span> <span class="n">normalize_fs_path</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="n">filepath</span><span class="p">))</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span>

    <span class="k">def</span><span class="w"> </span><span class="nf">_migrate_normalized_filepath</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">conn</span><span class="p">:</span> <span class="n">sqlite3</span><span class="o">.</span><span class="n">Connection</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Fix all filepath_normalized columns for unicode normalization&quot;&quot;&quot;</span>
        <span class="c1"># Prior to database version 4.3, filepath_normalized was not normalized for unicode</span>
        <span class="n">migration_sql</span> <span class="o">=</span> <span class="p">[</span>
<span class="w">            </span><span class="sd">&quot;&quot;&quot; CREATE TABLE IF NOT EXISTS files_migrate (</span>
<span class="sd">                    id INTEGER PRIMARY KEY,</span>
<span class="sd">                    filepath TEXT NOT NULL,</span>
<span class="sd">                    filepath_normalized TEXT NOT NULL,</span>
<span class="sd">                    uuid TEXT,</span>
<span class="sd">                    orig_mode INTEGER,</span>
<span class="sd">                    orig_size INTEGER,</span>
<span class="sd">                    orig_mtime REAL,</span>
<span class="sd">                    exif_mode INTEGER,</span>
<span class="sd">                    exif_size INTEGER,</span>
<span class="sd">                    exif_mtime REAL,</span>
<span class="sd">                    UNIQUE(filepath_normalized)</span>
<span class="sd">                    ); &quot;&quot;&quot;</span><span class="p">,</span>
<span class="w">            </span><span class="sd">&quot;&quot;&quot; INSERT INTO files_migrate SELECT * FROM files;&quot;&quot;&quot;</span><span class="p">,</span>
<span class="w">            </span><span class="sd">&quot;&quot;&quot; DROP TABLE files;&quot;&quot;&quot;</span><span class="p">,</span>
<span class="w">            </span><span class="sd">&quot;&quot;&quot; ALTER TABLE files_migrate RENAME TO files;&quot;&quot;&quot;</span><span class="p">,</span>
        <span class="p">]</span>

        <span class="k">with</span> <span class="bp">self</span><span class="o">.</span><span class="n">lock</span><span class="p">:</span>
            <span class="n">c</span> <span class="o">=</span> <span class="n">conn</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span>
            <span class="k">for</span> <span class="n">sql</span> <span class="ow">in</span> <span class="n">migration_sql</span><span class="p">:</span>
                <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="n">sql</span><span class="p">)</span>
            <span class="n">conn</span><span class="o">.</span><span class="n">commit</span><span class="p">()</span>

            <span class="k">for</span> <span class="n">table</span> <span class="ow">in</span> <span class="p">[</span><span class="s2">&quot;converted&quot;</span><span class="p">,</span> <span class="s2">&quot;edited&quot;</span><span class="p">,</span> <span class="s2">&quot;exifdata&quot;</span><span class="p">,</span> <span class="s2">&quot;files&quot;</span><span class="p">,</span> <span class="s2">&quot;sidecar&quot;</span><span class="p">]:</span>
                <span class="n">old_values</span> <span class="o">=</span> <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
                    <span class="sa">f</span><span class="s2">&quot;SELECT filepath_normalized, id FROM </span><span class="si">{</span><span class="n">table</span><span class="si">}</span><span class="s2">&quot;</span>
                <span class="p">)</span><span class="o">.</span><span class="n">fetchall</span><span class="p">()</span>
                <span class="n">new_values</span> <span class="o">=</span> <span class="p">[</span>
                    <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_normalize_filepath</span><span class="p">(</span><span class="n">filepath_normalized</span><span class="p">),</span> <span class="n">id_</span><span class="p">)</span>
                    <span class="k">for</span> <span class="n">filepath_normalized</span><span class="p">,</span> <span class="n">id_</span> <span class="ow">in</span> <span class="n">old_values</span>
                <span class="p">]</span>
                <span class="n">c</span><span class="o">.</span><span class="n">executemany</span><span class="p">(</span>
                    <span class="sa">f</span><span class="s2">&quot;UPDATE </span><span class="si">{</span><span class="n">table</span><span class="si">}</span><span class="s2"> SET filepath_normalized=? WHERE id=?&quot;</span><span class="p">,</span> <span class="n">new_values</span>
                <span class="p">)</span>
            <span class="n">conn</span><span class="o">.</span><span class="n">commit</span><span class="p">()</span>

    <span class="k">def</span><span class="w"> </span><span class="nf">_migrate_4_3_to_5_0</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">conn</span><span class="p">:</span> <span class="n">sqlite3</span><span class="o">.</span><span class="n">Connection</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Migrate database from version 4.3 to 5.0&quot;&quot;&quot;</span>
        <span class="k">with</span> <span class="bp">self</span><span class="o">.</span><span class="n">lock</span><span class="p">:</span>
            <span class="n">c</span> <span class="o">=</span> <span class="n">conn</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span>
            <span class="c1"># add metadata column to files to support --force-update</span>
            <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s2">&quot;ALTER TABLE files ADD COLUMN metadata TEXT;&quot;</span><span class="p">)</span>
            <span class="n">conn</span><span class="o">.</span><span class="n">commit</span><span class="p">()</span>

    <span class="k">def</span><span class="w"> </span><span class="nf">_migrate_5_0_to_6_0</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">conn</span><span class="p">:</span> <span class="n">sqlite3</span><span class="o">.</span><span class="n">Connection</span><span class="p">):</span>
        <span class="k">with</span> <span class="bp">self</span><span class="o">.</span><span class="n">lock</span><span class="p">:</span>
            <span class="n">c</span> <span class="o">=</span> <span class="n">conn</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span>
            <span class="c1"># add export_data table</span>
            <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
<span class="w">                </span><span class="sd">&quot;&quot;&quot; CREATE TABLE IF NOT EXISTS export_data(</span>
<span class="sd">                        id INTEGER PRIMARY KEY,</span>
<span class="sd">                        filepath_normalized TEXT NOT NULL,</span>
<span class="sd">                        filepath TEXT NOT NULL,</span>
<span class="sd">                        uuid TEXT NOT NULL,</span>
<span class="sd">                        src_mode INTEGER,</span>
<span class="sd">                        src_size INTEGER,</span>
<span class="sd">                        src_mtime REAL,</span>
<span class="sd">                        dest_mode INTEGER,</span>
<span class="sd">                        dest_size INTEGER,</span>
<span class="sd">                        dest_mtime REAL,</span>
<span class="sd">                        digest TEXT,</span>
<span class="sd">                        exifdata JSON,</span>
<span class="sd">                        export_options INTEGER,</span>
<span class="sd">                        UNIQUE(filepath_normalized)</span>
<span class="sd">                    ); &quot;&quot;&quot;</span><span class="p">,</span>
            <span class="p">)</span>
            <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
<span class="w">                </span><span class="sd">&quot;&quot;&quot; CREATE UNIQUE INDEX IF NOT EXISTS idx_export_data_filepath_normalized on export_data (filepath_normalized); &quot;&quot;&quot;</span><span class="p">,</span>
            <span class="p">)</span>

            <span class="c1"># migrate data</span>
            <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
<span class="w">                </span><span class="sd">&quot;&quot;&quot; INSERT INTO export_data (filepath_normalized, filepath, uuid) SELECT filepath_normalized, filepath, uuid FROM files;&quot;&quot;&quot;</span><span class="p">,</span>
            <span class="p">)</span>
            <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
<span class="w">                </span><span class="sd">&quot;&quot;&quot; UPDATE export_data</span>
<span class="sd">                    SET (src_mode, src_size, src_mtime) =</span>
<span class="sd">                    (SELECT mode, size, mtime</span>
<span class="sd">                    FROM edited</span>
<span class="sd">                    WHERE export_data.filepath_normalized = edited.filepath_normalized);</span>
<span class="sd">                &quot;&quot;&quot;</span><span class="p">,</span>
            <span class="p">)</span>
            <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
<span class="w">                </span><span class="sd">&quot;&quot;&quot; UPDATE export_data</span>
<span class="sd">                    SET (dest_mode, dest_size, dest_mtime) =</span>
<span class="sd">                    (SELECT orig_mode, orig_size, orig_mtime</span>
<span class="sd">                    FROM files</span>
<span class="sd">                    WHERE export_data.filepath_normalized = files.filepath_normalized);</span>
<span class="sd">                &quot;&quot;&quot;</span><span class="p">,</span>
            <span class="p">)</span>
            <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
<span class="w">                </span><span class="sd">&quot;&quot;&quot; UPDATE export_data SET digest =</span>
<span class="sd">                            (SELECT metadata FROM files</span>
<span class="sd">                            WHERE files.filepath_normalized = export_data.filepath_normalized</span>
<span class="sd">                            ); &quot;&quot;&quot;</span>
            <span class="p">)</span>
            <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
<span class="w">                </span><span class="sd">&quot;&quot;&quot; UPDATE export_data SET exifdata =</span>
<span class="sd">                            (SELECT json_exifdata FROM exifdata</span>
<span class="sd">                            WHERE exifdata.filepath_normalized = export_data.filepath_normalized</span>
<span class="sd">                            ); &quot;&quot;&quot;</span>
            <span class="p">)</span>

            <span class="c1"># create config table</span>
            <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
<span class="w">                </span><span class="sd">&quot;&quot;&quot; CREATE TABLE IF NOT EXISTS config (</span>
<span class="sd">                        id INTEGER PRIMARY KEY,</span>
<span class="sd">                        datetime TEXT,</span>
<span class="sd">                        config TEXT</span>
<span class="sd">                ); &quot;&quot;&quot;</span>
            <span class="p">)</span>

            <span class="c1"># create photoinfo table</span>
            <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
<span class="w">                </span><span class="sd">&quot;&quot;&quot; CREATE TABLE IF NOT EXISTS photoinfo (</span>
<span class="sd">                        id INTEGER PRIMARY KEY,</span>
<span class="sd">                        uuid TEXT NOT NULL,</span>
<span class="sd">                        photoinfo JSON,</span>
<span class="sd">                        UNIQUE(uuid)</span>
<span class="sd">                ); &quot;&quot;&quot;</span>
            <span class="p">)</span>
            <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
<span class="w">                </span><span class="sd">&quot;&quot;&quot;CREATE UNIQUE INDEX IF NOT EXISTS idx_photoinfo_uuid on photoinfo (uuid);&quot;&quot;&quot;</span>
            <span class="p">)</span>
            <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
<span class="w">                </span><span class="sd">&quot;&quot;&quot; INSERT INTO photoinfo (uuid, photoinfo) SELECT uuid, json_info FROM info;&quot;&quot;&quot;</span>
            <span class="p">)</span>

            <span class="c1"># drop indexes no longer needed</span>
            <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s2">&quot;DROP INDEX IF EXISTS idx_files_filepath_normalized;&quot;</span><span class="p">)</span>
            <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s2">&quot;DROP INDEX IF EXISTS idx_exifdata_filename;&quot;</span><span class="p">)</span>
            <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s2">&quot;DROP INDEX IF EXISTS idx_edited_filename;&quot;</span><span class="p">)</span>
            <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s2">&quot;DROP INDEX IF EXISTS idx_converted_filename;&quot;</span><span class="p">)</span>
            <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s2">&quot;DROP INDEX IF EXISTS idx_sidecar_filename;&quot;</span><span class="p">)</span>
            <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s2">&quot;DROP INDEX IF EXISTS idx_detected_text;&quot;</span><span class="p">)</span>

            <span class="c1"># drop tables no longer needed</span>
            <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s2">&quot;DROP TABLE IF EXISTS files;&quot;</span><span class="p">)</span>
            <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s2">&quot;DROP TABLE IF EXISTS info;&quot;</span><span class="p">)</span>
            <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s2">&quot;DROP TABLE IF EXISTS exifdata;&quot;</span><span class="p">)</span>
            <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s2">&quot;DROP TABLE IF EXISTS edited;&quot;</span><span class="p">)</span>
            <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s2">&quot;DROP TABLE IF EXISTS converted;&quot;</span><span class="p">)</span>
            <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s2">&quot;DROP TABLE IF EXISTS sidecar;&quot;</span><span class="p">)</span>
            <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s2">&quot;DROP TABLE IF EXISTS detected_text;&quot;</span><span class="p">)</span>

            <span class="n">conn</span><span class="o">.</span><span class="n">commit</span><span class="p">()</span>

    <span class="k">def</span><span class="w"> </span><span class="nf">_migrate_6_0_to_7_0</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">conn</span><span class="p">:</span> <span class="n">sqlite3</span><span class="o">.</span><span class="n">Connection</span><span class="p">):</span>
        <span class="k">with</span> <span class="bp">self</span><span class="o">.</span><span class="n">lock</span><span class="p">:</span>
            <span class="n">c</span> <span class="o">=</span> <span class="n">conn</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span>
            <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
<span class="w">                </span><span class="sd">&quot;&quot;&quot;CREATE TABLE IF NOT EXISTS export_results_data (</span>
<span class="sd">                        id INTEGER PRIMARY KEY,</span>
<span class="sd">                        datetime TEXT,</span>
<span class="sd">                        export_results BLOB</span>
<span class="sd">                );&quot;&quot;&quot;</span>
            <span class="p">)</span>
            <span class="c1"># pre-populate report_data table with blank fields</span>
            <span class="c1"># ExportDB will use these as circular buffer always writing to the oldest record</span>
            <span class="k">for</span> <span class="n">_</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">MAX_EXPORT_RESULTS_DATA_ROWS</span><span class="p">):</span>
                <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
<span class="w">                    </span><span class="sd">&quot;&quot;&quot;INSERT INTO export_results_data (datetime, export_results) VALUES (?, ?);&quot;&quot;&quot;</span><span class="p">,</span>
                    <span class="p">(</span><span class="n">datetime</span><span class="o">.</span><span class="n">datetime</span><span class="o">.</span><span class="n">now</span><span class="p">()</span><span class="o">.</span><span class="n">isoformat</span><span class="p">(),</span> <span class="sa">b</span><span class="s2">&quot;&quot;</span><span class="p">),</span>
                <span class="p">)</span>
                <span class="c1"># sleep a tiny bit just to ensure time stamps increment</span>
                <span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mf">0.001</span><span class="p">)</span>
            <span class="n">conn</span><span class="o">.</span><span class="n">commit</span><span class="p">()</span>

    <span class="k">def</span><span class="w"> </span><span class="nf">_migrate_7_0_to_7_1</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">conn</span><span class="p">:</span> <span class="n">sqlite3</span><span class="o">.</span><span class="n">Connection</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Add timestamp column to export_data table and triggers to update it on insert and update.&quot;&quot;&quot;</span>
        <span class="k">with</span> <span class="bp">self</span><span class="o">.</span><span class="n">lock</span><span class="p">:</span>
            <span class="n">c</span> <span class="o">=</span> <span class="n">conn</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span>
            <span class="c1"># timestamp column should not exist but this prevents error if migration is run on an already migrated database</span>
            <span class="c1"># reference #794</span>
            <span class="n">results</span> <span class="o">=</span> <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
                <span class="s2">&quot;SELECT COUNT(*) FROM pragma_table_info(&#39;export_data&#39;) WHERE name=&#39;timestamp&#39;;&quot;</span>
            <span class="p">)</span><span class="o">.</span><span class="n">fetchone</span><span class="p">()</span>
            <span class="k">if</span> <span class="n">results</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
                <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s2">&quot;&quot;&quot;ALTER TABLE export_data ADD COLUMN timestamp DATETIME;&quot;&quot;&quot;</span><span class="p">)</span>
            <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
<span class="w">                </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd">                CREATE TRIGGER IF NOT EXISTS insert_timestamp_trigger</span>
<span class="sd">                AFTER INSERT ON export_data</span>
<span class="sd">                BEGIN</span>
<span class="sd">                    UPDATE export_data SET timestamp = STRFTIME(&#39;%Y-%m-%d %H:%M:%f&#39;, &#39;NOW&#39;) WHERE id = NEW.id;</span>
<span class="sd">                END;</span>
<span class="sd">                &quot;&quot;&quot;</span>
            <span class="p">)</span>
            <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
<span class="w">                </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd">                CREATE TRIGGER IF NOT EXISTS update_timestamp_trigger</span>
<span class="sd">                AFTER UPDATE On export_data</span>
<span class="sd">                BEGIN</span>
<span class="sd">                    UPDATE export_data SET timestamp = STRFTIME(&#39;%Y-%m-%d %H:%M:%f&#39;, &#39;NOW&#39;) WHERE id = NEW.id;</span>
<span class="sd">                END;</span>
<span class="sd">                &quot;&quot;&quot;</span>
            <span class="p">)</span>
            <span class="n">conn</span><span class="o">.</span><span class="n">commit</span><span class="p">()</span>

    <span class="k">def</span><span class="w"> </span><span class="nf">_migrate_7_1_to_8_0</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">conn</span><span class="p">:</span> <span class="n">sqlite3</span><span class="o">.</span><span class="n">Connection</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Add error column to export_data table&quot;&quot;&quot;</span>
        <span class="k">with</span> <span class="bp">self</span><span class="o">.</span><span class="n">lock</span><span class="p">:</span>
            <span class="n">c</span> <span class="o">=</span> <span class="n">conn</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span>
            <span class="n">results</span> <span class="o">=</span> <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
                <span class="s2">&quot;SELECT COUNT(*) FROM pragma_table_info(&#39;export_data&#39;) WHERE name=&#39;error&#39;;&quot;</span>
            <span class="p">)</span><span class="o">.</span><span class="n">fetchone</span><span class="p">()</span>
            <span class="k">if</span> <span class="n">results</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
                <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s2">&quot;&quot;&quot;ALTER TABLE export_data ADD COLUMN error JSON;&quot;&quot;&quot;</span><span class="p">)</span>
            <span class="n">conn</span><span class="o">.</span><span class="n">commit</span><span class="p">()</span>

    <span class="k">def</span><span class="w"> </span><span class="nf">_migrate_8_0_to_9_0</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">conn</span><span class="p">:</span> <span class="n">sqlite3</span><span class="o">.</span><span class="n">Connection</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Add history table&quot;&quot;&quot;</span>
        <span class="k">with</span> <span class="bp">self</span><span class="o">.</span><span class="n">lock</span><span class="p">:</span>
            <span class="n">c</span> <span class="o">=</span> <span class="n">conn</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span>

            <span class="c1"># the export_data table does not contain data on missing files</span>
            <span class="c1"># so create a history_paths table to track every path that has ever</span>
            <span class="c1"># been exported or attempted to export (but was missing)</span>
            <span class="c1"># so this can be used by history table to find the associated file path</span>
            <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
<span class="w">                </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd">            CREATE TABLE IF NOT EXISTS history_path (</span>
<span class="sd">                id INTEGER PRIMARY KEY,</span>
<span class="sd">                filepath_normalized TEXT NOT NULL,</span>
<span class="sd">                uuid TEXT NOT NULL</span>
<span class="sd">            );</span>
<span class="sd">            &quot;&quot;&quot;</span>
            <span class="p">)</span>

            <span class="c1"># filepath_id is foreign key to history_path table</span>
            <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
<span class="w">                </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd">            CREATE TABLE IF NOT EXISTS history (</span>
<span class="sd">                      id INTEGER PRIMARY KEY,</span>
<span class="sd">                      filepath_id INTEGER,</span>
<span class="sd">                      datetime DATETIME,</span>
<span class="sd">                      action TEXT,</span>
<span class="sd">                      diff JSON</span>
<span class="sd">                    );</span>
<span class="sd">            &quot;&quot;&quot;</span>
            <span class="p">)</span>

            <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
<span class="w">                </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd">                CREATE TRIGGER IF NOT EXISTS insert_history_datetime_trigger</span>
<span class="sd">                AFTER INSERT ON history</span>
<span class="sd">                BEGIN</span>
<span class="sd">                    UPDATE history SET datetime = STRFTIME(&#39;%Y-%m-%d %H:%M:%f&#39;, &#39;NOW&#39;) WHERE id = NEW.id;</span>
<span class="sd">                END;</span>
<span class="sd">                &quot;&quot;&quot;</span>
            <span class="p">)</span>

            <span class="n">conn</span><span class="o">.</span><span class="n">commit</span><span class="p">()</span>

    <span class="k">def</span><span class="w"> </span><span class="nf">_migrate_9_0_to_9_1</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">conn</span><span class="p">:</span> <span class="n">sqlite3</span><span class="o">.</span><span class="n">Connection</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Add history index&quot;&quot;&quot;</span>
        <span class="k">with</span> <span class="bp">self</span><span class="o">.</span><span class="n">lock</span><span class="p">:</span>
            <span class="n">c</span> <span class="o">=</span> <span class="n">conn</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span>

            <span class="c1"># add index to the history_path table</span>
            <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
<span class="w">                </span><span class="sd">&quot;&quot;&quot; CREATE UNIQUE INDEX IF NOT EXISTS</span>
<span class="sd">                    idx_history_path_filepath_normalized</span>
<span class="sd">                    ON history_path (filepath_normalized);</span>
<span class="sd">                    &quot;&quot;&quot;</span>
            <span class="p">)</span>

            <span class="n">conn</span><span class="o">.</span><span class="n">commit</span><span class="p">()</span>

    <span class="k">def</span><span class="w"> </span><span class="nf">_migrate_9_1_to_10_0</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">conn</span><span class="p">:</span> <span class="n">sqlite3</span><span class="o">.</span><span class="n">Connection</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Add export_directory table&quot;&quot;&quot;</span>
        <span class="k">with</span> <span class="bp">self</span><span class="o">.</span><span class="n">lock</span><span class="p">:</span>
            <span class="n">c</span> <span class="o">=</span> <span class="n">conn</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span>

            <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
<span class="w">                </span><span class="sd">&quot;&quot;&quot; CREATE TABLE IF NOT EXISTS export_directory (</span>
<span class="sd">                    id INTEGER PRIMARY KEY,</span>
<span class="sd">                    export_directory TEXT</span>
<span class="sd">                    );</span>
<span class="sd">                    &quot;&quot;&quot;</span>
            <span class="p">)</span>

            <span class="n">conn</span><span class="o">.</span><span class="n">commit</span><span class="p">()</span>

    <span class="k">def</span><span class="w"> </span><span class="nf">_migrate_10_0_to_10_1</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">conn</span><span class="p">:</span> <span class="n">sqlite3</span><span class="o">.</span><span class="n">Connection</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Add history related indexes&quot;&quot;&quot;</span>
        <span class="k">with</span> <span class="bp">self</span><span class="o">.</span><span class="n">lock</span><span class="p">:</span>
            <span class="n">c</span> <span class="o">=</span> <span class="n">conn</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span>

            <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
<span class="w">                </span><span class="sd">&quot;&quot;&quot; CREATE INDEX IF NOT EXISTS idx_history_filepath_id</span>
<span class="sd">                    ON history (filepath_id);</span>
<span class="sd">                    &quot;&quot;&quot;</span>
            <span class="p">)</span>

            <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
<span class="w">                </span><span class="sd">&quot;&quot;&quot; CREATE INDEX IF NOT EXISTS idx_history_path_uuid</span>
<span class="sd">                    ON history_path (uuid);</span>
<span class="sd">                    &quot;&quot;&quot;</span>
            <span class="p">)</span>

            <span class="n">conn</span><span class="o">.</span><span class="n">commit</span><span class="p">()</span>

    <span class="k">def</span><span class="w"> </span><span class="nf">_perform_db_maintenance</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">conn</span><span class="p">:</span> <span class="n">sqlite3</span><span class="o">.</span><span class="n">Connection</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Perform database maintenance&quot;&quot;&quot;</span>
        <span class="k">if</span> <span class="nb">float</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">version</span><span class="p">)</span> <span class="o">&lt;</span> <span class="nb">float</span><span class="p">(</span><span class="s2">&quot;6.0&quot;</span><span class="p">):</span>
            <span class="k">return</span>
        <span class="k">with</span> <span class="bp">self</span><span class="o">.</span><span class="n">lock</span><span class="p">:</span>
            <span class="n">c</span> <span class="o">=</span> <span class="n">conn</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span>
            <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
<span class="w">                </span><span class="sd">&quot;&quot;&quot;DELETE FROM config</span>
<span class="sd">                    WHERE id &lt; (</span>
<span class="sd">                        SELECT MIN(id)</span>
<span class="sd">                        FROM (SELECT id FROM config ORDER BY id DESC LIMIT 9)</span>
<span class="sd">                    );</span>
<span class="sd">                &quot;&quot;&quot;</span>
            <span class="p">)</span>
            <span class="n">conn</span><span class="o">.</span><span class="n">commit</span><span class="p">()</span></div>



<span class="k">class</span><span class="w"> </span><span class="nc">ExportDBInMemory</span><span class="p">(</span><span class="n">ExportDB</span><span class="p">):</span>
<span class="w">    </span><span class="sd">&quot;&quot;&quot;In memory version of ExportDB</span>

<span class="sd">    Args:</span>
<span class="sd">        dbfile: path to osxphotos export database file</span>
<span class="sd">        export_dir: path to directory where exported files are stored; if None will read value from database</span>
<span class="sd">        version: if supplied, creates database with this version; otherwise uses current version;</span>
<span class="sd">            (must be &gt;= &quot;4.3&quot; and &lt;= OSXPHOTOS_EXPORTDB_VERSION)</span>
<span class="sd">            For testing only; in normal usage, omit this argument</span>

<span class="sd">    Note:</span>
<span class="sd">        Copies the on-disk database into memory so it may be operated on without modifying the on-disk version</span>
<span class="sd">        export_dir = None must only be used when opening an existing database to read and not to export</span>
<span class="sd">    &quot;&quot;&quot;</span>

    <span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span>
        <span class="bp">self</span><span class="p">,</span>
        <span class="n">dbfile</span><span class="p">:</span> <span class="nb">str</span> <span class="o">|</span> <span class="n">os</span><span class="o">.</span><span class="n">PathLike</span><span class="p">,</span>
        <span class="n">export_dir</span><span class="p">:</span> <span class="nb">str</span> <span class="o">|</span> <span class="n">os</span><span class="o">.</span><span class="n">PathLike</span> <span class="o">|</span> <span class="kc">None</span><span class="p">,</span>
        <span class="n">version</span><span class="p">:</span> <span class="nb">str</span> <span class="o">|</span> <span class="kc">None</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span>
    <span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot; &quot;Initialize ExportDBInMemory</span>

<span class="sd">        Args:</span>
<span class="sd">            dbfile: path to osxphotos export database file</span>
<span class="sd">            export_dir: path to directory where exported files are stored; if None will read value from database</span>
<span class="sd">            version: if supplied, creates database with this version; otherwise uses current version;</span>
<span class="sd">                (must be &gt;= &quot;4.3&quot; and &lt;= OSXPHOTOS_EXPORTDB_VERSION)</span>
<span class="sd">                For testing only; in normal usage, omit this argument</span>

<span class="sd">        Note: export_dir = None must only be used when opening an existing database to read and not to export</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_dbfile</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="n">dbfile</span><span class="p">)</span> <span class="ow">or</span> <span class="sa">f</span><span class="s2">&quot;./</span><span class="si">{</span><span class="n">OSXPHOTOS_EXPORT_DB</span><span class="si">}</span><span class="s2">&quot;</span>

        <span class="c1"># export_dir allows the database to located in a different path than the export</span>
        <span class="c1"># all paths are stored as relative paths to this path</span>
        <span class="c1"># this allows the entire export tree to be moved to a new disk/location</span>
        <span class="c1"># whilst preserving the UUID to filename mapping</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_path</span><span class="p">:</span> <span class="nb">str</span> <span class="o">|</span> <span class="kc">None</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="n">export_dir</span><span class="p">)</span> <span class="k">if</span> <span class="n">export_dir</span> <span class="k">else</span> <span class="kc">None</span>

        <span class="bp">self</span><span class="o">.</span><span class="n">was_upgraded</span><span class="p">:</span> <span class="nb">tuple</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="nb">str</span><span class="p">]</span> <span class="o">|</span> <span class="nb">tuple</span> <span class="o">=</span> <span class="p">()</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">was_created</span> <span class="o">=</span> <span class="kc">False</span>

        <span class="bp">self</span><span class="o">.</span><span class="n">lock</span> <span class="o">=</span> <span class="n">threading</span><span class="o">.</span><span class="n">Lock</span><span class="p">()</span>

        <span class="bp">self</span><span class="o">.</span><span class="n">_conn</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_open_export_db</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_dbfile</span><span class="p">,</span> <span class="n">version</span><span class="o">=</span><span class="n">version</span><span class="p">)</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_insert_run_info</span><span class="p">()</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_insert_export_dir</span><span class="p">()</span>

    <span class="nd">@retry</span><span class="p">(</span><span class="n">stop</span><span class="o">=</span><span class="n">stop_after_attempt</span><span class="p">(</span><span class="n">MAX_RETRY_ATTEMPTS</span><span class="p">))</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">write_to_disk</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Write changes from in-memory database back to disk&quot;&quot;&quot;</span>

        <span class="c1"># dump the database</span>
        <span class="k">with</span> <span class="bp">self</span><span class="o">.</span><span class="n">lock</span><span class="p">:</span>
            <span class="n">conn</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">connection</span>
            <span class="n">conn</span><span class="o">.</span><span class="n">commit</span><span class="p">()</span>

            <span class="c1"># backup the old database to disk</span>
            <span class="c1"># this is just in case the write fails</span>
            <span class="c1"># so the user can recover the database</span>
            <span class="k">try</span><span class="p">:</span>
                <span class="n">sqlite_backup_dbfiles</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_dbfile</span><span class="p">)</span>
            <span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
                <span class="n">logger</span><span class="o">.</span><span class="n">warning</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Error backing up export db: </span><span class="si">{</span><span class="n">e</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>

            <span class="c1"># delete the old database if it exists</span>
            <span class="k">if</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">isfile</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_dbfile</span><span class="p">):</span>
                <span class="n">sqlite_delete_dbfiles</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_dbfile</span><span class="p">)</span>

            <span class="c1"># write the new database to disk</span>
            <span class="n">conn_on_disk</span> <span class="o">=</span> <span class="n">sqlite3</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span>
                <span class="nb">str</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_dbfile</span><span class="p">),</span> <span class="n">check_same_thread</span><span class="o">=</span><span class="n">SQLITE_CHECK_SAME_THREAD</span>
            <span class="p">)</span>
            <span class="n">conn</span><span class="o">.</span><span class="n">backup</span><span class="p">(</span><span class="n">conn_on_disk</span><span class="p">,</span> <span class="n">pages</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span>
            <span class="n">conn_on_disk</span><span class="o">.</span><span class="n">commit</span><span class="p">()</span>
            <span class="n">conn_on_disk</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>

            <span class="c1"># delete the backup</span>
            <span class="k">try</span><span class="p">:</span>
                <span class="n">sqlite_delete_backup_files</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_dbfile</span><span class="p">)</span>
            <span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
                <span class="n">logger</span><span class="o">.</span><span class="n">warning</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Error deleting export database backup: </span><span class="si">{</span><span class="n">e</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>

    <span class="nd">@retry</span><span class="p">(</span>
        <span class="n">stop</span><span class="o">=</span><span class="n">stop_after_attempt</span><span class="p">(</span><span class="n">MAX_RETRY_ATTEMPTS</span><span class="p">),</span>
        <span class="n">retry_error_callback</span><span class="o">=</span><span class="n">retry_log_error_no_raise</span><span class="p">,</span>  <span class="c1"># #999</span>
    <span class="p">)</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">close</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;close the database connection&quot;&quot;&quot;</span>
        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_conn</span><span class="p">:</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_conn</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_conn</span> <span class="o">=</span> <span class="kc">None</span>

    <span class="nd">@retry</span><span class="p">(</span><span class="n">stop</span><span class="o">=</span><span class="n">stop_after_attempt</span><span class="p">(</span><span class="n">MAX_RETRY_ATTEMPTS</span><span class="p">))</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">_open_export_db</span><span class="p">(</span>
        <span class="bp">self</span><span class="p">,</span> <span class="n">dbfile</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">version</span><span class="p">:</span> <span class="nb">str</span> <span class="o">|</span> <span class="kc">None</span> <span class="o">=</span> <span class="kc">None</span>
    <span class="p">):</span>  <span class="c1"># sourcery skip: raise-specific-error</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Open export database and return a db connection</span>

<span class="sd">        Args:</span>
<span class="sd">            dbfile: path to database file</span>
<span class="sd">            version: database version to create if database doesn&#39;t exist</span>

<span class="sd">        Returns: connection to the database</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="k">if</span> <span class="ow">not</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">isfile</span><span class="p">(</span><span class="n">dbfile</span><span class="p">):</span>
            <span class="c1"># database doesn&#39;t exist so create it in-memory</span>
            <span class="n">src</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_db_connection</span><span class="p">()</span>
            <span class="k">if</span> <span class="ow">not</span> <span class="n">src</span><span class="p">:</span>
                <span class="k">raise</span> <span class="ne">Exception</span><span class="p">(</span><span class="s2">&quot;Error getting connection to in-memory database&quot;</span><span class="p">)</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_create_or_migrate_db_tables</span><span class="p">(</span><span class="n">src</span><span class="p">,</span> <span class="n">version</span><span class="o">=</span><span class="n">version</span><span class="p">)</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">was_created</span> <span class="o">=</span> <span class="kc">True</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">was_upgraded</span> <span class="o">=</span> <span class="p">()</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">version</span> <span class="o">=</span> <span class="n">OSXPHOTOS_EXPORTDB_VERSION</span>
            <span class="k">return</span> <span class="n">src</span>

        <span class="k">if</span> <span class="n">version</span><span class="p">:</span>
            <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s2">&quot;Cannot specify version when opening an existing database&quot;</span><span class="p">)</span>

        <span class="c1"># database exists so copy it to memory</span>
        <span class="n">src</span> <span class="o">=</span> <span class="n">sqlite3</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">dbfile</span><span class="p">,</span> <span class="n">check_same_thread</span><span class="o">=</span><span class="n">SQLITE_CHECK_SAME_THREAD</span><span class="p">)</span>

        <span class="c1"># Create a database in memory by backing up the on-disk database</span>
        <span class="n">dst</span> <span class="o">=</span> <span class="n">sqlite3</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="s2">&quot;:memory:&quot;</span><span class="p">,</span> <span class="n">check_same_thread</span><span class="o">=</span><span class="n">SQLITE_CHECK_SAME_THREAD</span><span class="p">)</span>
        <span class="k">with</span> <span class="n">dst</span><span class="p">:</span>
            <span class="n">src</span><span class="o">.</span><span class="n">backup</span><span class="p">(</span><span class="n">dst</span><span class="p">,</span> <span class="n">pages</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span>
        <span class="n">src</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>

        <span class="bp">self</span><span class="o">.</span><span class="n">was_created</span> <span class="o">=</span> <span class="kc">False</span>
        <span class="n">version_info</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_database_version</span><span class="p">(</span><span class="n">dst</span><span class="p">)</span>
        <span class="k">if</span> <span class="nb">float</span><span class="p">(</span><span class="n">version_info</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span> <span class="o">&lt;</span> <span class="nb">float</span><span class="p">(</span><span class="n">OSXPHOTOS_EXPORTDB_VERSION</span><span class="p">):</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_create_or_migrate_db_tables</span><span class="p">(</span><span class="n">dst</span><span class="p">)</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">was_upgraded</span> <span class="o">=</span> <span class="p">(</span><span class="n">version_info</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">OSXPHOTOS_EXPORTDB_VERSION</span><span class="p">)</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">was_upgraded</span> <span class="o">=</span> <span class="p">()</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">version</span> <span class="o">=</span> <span class="n">OSXPHOTOS_EXPORTDB_VERSION</span>

        <span class="k">return</span> <span class="n">dst</span>

    <span class="k">def</span><span class="w"> </span><span class="nf">_get_db_connection</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;return db connection to in memory database&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="n">sqlite3</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="s2">&quot;:memory:&quot;</span><span class="p">,</span> <span class="n">check_same_thread</span><span class="o">=</span><span class="n">SQLITE_CHECK_SAME_THREAD</span><span class="p">)</span>

    <span class="k">def</span><span class="w"> </span><span class="nf">_dump_db</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">conn</span><span class="p">:</span> <span class="n">sqlite3</span><span class="o">.</span><span class="n">Connection</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">StringIO</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;dump sqlite db to a string buffer&quot;&quot;&quot;</span>

        <span class="n">dbdump</span> <span class="o">=</span> <span class="n">StringIO</span><span class="p">()</span>
        <span class="k">for</span> <span class="n">line</span> <span class="ow">in</span> <span class="n">conn</span><span class="o">.</span><span class="n">iterdump</span><span class="p">():</span>
            <span class="n">dbdump</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s2">&quot;</span><span class="si">%s</span><span class="se">\n</span><span class="s2">&quot;</span> <span class="o">%</span> <span class="n">line</span><span class="p">)</span>
        <span class="n">dbdump</span><span class="o">.</span><span class="n">seek</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
        <span class="k">return</span> <span class="n">dbdump</span>

    <span class="k">def</span><span class="w"> </span><span class="fm">__del__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;close the database connection&quot;&quot;&quot;</span>
        <span class="k">with</span> <span class="n">suppress</span><span class="p">(</span><span class="n">Error</span><span class="p">):</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>


<div class="viewcode-block" id="ExportDBTemp">
<a class="viewcode-back" href="../../reference.html#osxphotos.ExportDBTemp">[docs]</a>
<span class="k">class</span><span class="w"> </span><span class="nc">ExportDBTemp</span><span class="p">(</span><span class="n">ExportDBInMemory</span><span class="p">):</span>
<span class="w">    </span><span class="sd">&quot;&quot;&quot;Temporary in-memory version of ExportDB</span>

<span class="sd">    Args:</span>
<span class="sd">        version: if supplied, creates database with this version; otherwise uses current version;</span>
<span class="sd">            (must be &gt;= &quot;4.3&quot; and &lt;= OSXPHOTOS_EXPORTDB_VERSION)</span>
<span class="sd">            For testing only; in normal usage, omit this argument</span>
<span class="sd">    &quot;&quot;&quot;</span>

    <span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">version</span><span class="p">:</span> <span class="nb">str</span> <span class="o">|</span> <span class="kc">None</span> <span class="o">=</span> <span class="kc">None</span><span class="p">):</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_dbfile</span> <span class="o">=</span> <span class="s2">&quot;:memory:&quot;</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_path</span> <span class="o">=</span> <span class="s2">&quot;./&quot;</span>

        <span class="bp">self</span><span class="o">.</span><span class="n">lock</span> <span class="o">=</span> <span class="n">threading</span><span class="o">.</span><span class="n">Lock</span><span class="p">()</span>

        <span class="bp">self</span><span class="o">.</span><span class="n">was_upgraded</span> <span class="o">=</span> <span class="p">()</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">was_created</span> <span class="o">=</span> <span class="kc">False</span>

        <span class="bp">self</span><span class="o">.</span><span class="n">_conn</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_open_export_db</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_dbfile</span><span class="p">,</span> <span class="n">version</span><span class="p">)</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_insert_run_info</span><span class="p">()</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_insert_export_dir</span><span class="p">()</span>

    <span class="k">def</span><span class="w"> </span><span class="nf">_relative_filepath</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">filepath</span><span class="p">:</span> <span class="nb">str</span> <span class="o">|</span> <span class="n">os</span><span class="o">.</span><span class="n">PathLike</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Overrides _relative_filepath to return a path for use in the temp db&quot;&quot;&quot;</span>
        <span class="n">filepath</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="n">filepath</span><span class="p">)</span>
        <span class="k">return</span> <span class="n">filepath</span><span class="p">[</span><span class="mi">1</span><span class="p">:]</span> <span class="k">if</span> <span class="n">filepath</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&quot;/&quot;</span> <span class="k">else</span> <span class="n">filepath</span></div>



<span class="k">class</span><span class="w"> </span><span class="nc">ExportRecord</span><span class="p">:</span>
<span class="w">    </span><span class="sd">&quot;&quot;&quot;ExportRecord class&quot;&quot;&quot;</span>

    <span class="c1"># Implementation note:all properties and setters must be aware of whether or not running</span>
    <span class="c1"># as a context manager. If running as a context manager, the lock is not acquired by the</span>
    <span class="c1"># getter/setter as the lock is acquired by the context manager.  If not running as a</span>
    <span class="c1"># context manager, the lock is acquired by the getter/setter.</span>

    <span class="vm">__slots__</span> <span class="o">=</span> <span class="p">[</span>
        <span class="s2">&quot;_conn&quot;</span><span class="p">,</span>
        <span class="s2">&quot;_context_manager&quot;</span><span class="p">,</span>
        <span class="s2">&quot;_filepath_normalized&quot;</span><span class="p">,</span>
        <span class="s2">&quot;lock&quot;</span><span class="p">,</span>
    <span class="p">]</span>

    <span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span>
        <span class="bp">self</span><span class="p">,</span> <span class="n">conn</span><span class="p">:</span> <span class="n">sqlite3</span><span class="o">.</span><span class="n">Connection</span><span class="p">,</span> <span class="n">lock</span><span class="p">:</span> <span class="n">threading</span><span class="o">.</span><span class="n">Lock</span><span class="p">,</span> <span class="n">filepath_normalized</span><span class="p">:</span> <span class="nb">str</span>
    <span class="p">):</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_conn</span> <span class="o">=</span> <span class="n">conn</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">lock</span> <span class="o">=</span> <span class="n">lock</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_filepath_normalized</span> <span class="o">=</span> <span class="n">filepath_normalized</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_context_manager</span> <span class="o">=</span> <span class="kc">False</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">connection</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">sqlite3</span><span class="o">.</span><span class="n">Connection</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;return connection&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_conn</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">filepath</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;return filepath&quot;&quot;&quot;</span>
        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_context_manager</span><span class="p">:</span>
            <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_filepath</span><span class="p">()</span>
        <span class="k">with</span> <span class="bp">self</span><span class="o">.</span><span class="n">lock</span><span class="p">:</span>
            <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_filepath</span><span class="p">()</span>

    <span class="k">def</span><span class="w"> </span><span class="nf">_filepath</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;return filepath&quot;&quot;&quot;</span>
        <span class="n">conn</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">connection</span>
        <span class="n">c</span> <span class="o">=</span> <span class="n">conn</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span>
        <span class="k">if</span> <span class="n">row</span> <span class="o">:=</span> <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
            <span class="s2">&quot;SELECT filepath FROM export_data WHERE filepath_normalized = ?;&quot;</span><span class="p">,</span>
            <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_filepath_normalized</span><span class="p">,),</span>
        <span class="p">)</span><span class="o">.</span><span class="n">fetchone</span><span class="p">():</span>
            <span class="k">return</span> <span class="n">row</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>

        <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span>
            <span class="sa">f</span><span class="s2">&quot;No filepath found in database for </span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">_filepath_normalized</span><span class="si">}</span><span class="s2">&quot;</span>
        <span class="p">)</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">filepath_normalized</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;return filepath_normalized&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_filepath_normalized</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">uuid</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;return uuid&quot;&quot;&quot;</span>
        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_context_manager</span><span class="p">:</span>
            <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_uuid</span><span class="p">()</span>
        <span class="k">with</span> <span class="bp">self</span><span class="o">.</span><span class="n">lock</span><span class="p">:</span>
            <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_uuid</span><span class="p">()</span>

    <span class="k">def</span><span class="w"> </span><span class="nf">_uuid</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;return uuid&quot;&quot;&quot;</span>
        <span class="n">conn</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">connection</span>
        <span class="n">c</span> <span class="o">=</span> <span class="n">conn</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span>
        <span class="k">if</span> <span class="n">row</span> <span class="o">:=</span> <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
            <span class="s2">&quot;SELECT uuid FROM export_data WHERE filepath_normalized = ?;&quot;</span><span class="p">,</span>
            <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_filepath_normalized</span><span class="p">,),</span>
        <span class="p">)</span><span class="o">.</span><span class="n">fetchone</span><span class="p">():</span>
            <span class="k">return</span> <span class="n">row</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>

        <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;No uuid found in database for </span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">_filepath_normalized</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">digest</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;returns the digest value&quot;&quot;&quot;</span>
        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_context_manager</span><span class="p">:</span>
            <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_digest</span><span class="p">()</span>
        <span class="k">with</span> <span class="bp">self</span><span class="o">.</span><span class="n">lock</span><span class="p">:</span>
            <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_digest</span><span class="p">()</span>

    <span class="nd">@digest</span><span class="o">.</span><span class="n">setter</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">digest</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">value</span><span class="p">:</span> <span class="nb">str</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;set digest value&quot;&quot;&quot;</span>
        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_context_manager</span><span class="p">:</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_digest_setter</span><span class="p">(</span><span class="n">value</span><span class="p">)</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="k">with</span> <span class="bp">self</span><span class="o">.</span><span class="n">lock</span><span class="p">:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_digest_setter</span><span class="p">(</span><span class="n">value</span><span class="p">)</span>

    <span class="k">def</span><span class="w"> </span><span class="nf">_digest</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;returns the digest value&quot;&quot;&quot;</span>
        <span class="n">conn</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">connection</span>
        <span class="n">c</span> <span class="o">=</span> <span class="n">conn</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span>
        <span class="k">if</span> <span class="n">row</span> <span class="o">:=</span> <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
            <span class="s2">&quot;SELECT digest FROM export_data WHERE filepath_normalized = ?;&quot;</span><span class="p">,</span>
            <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_filepath_normalized</span><span class="p">,),</span>
        <span class="p">)</span><span class="o">.</span><span class="n">fetchone</span><span class="p">():</span>
            <span class="k">return</span> <span class="n">row</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>

        <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;No digest found in database for </span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">_filepath_normalized</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>

    <span class="k">def</span><span class="w"> </span><span class="nf">_digest_setter</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">value</span><span class="p">:</span> <span class="nb">str</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;set digest value&quot;&quot;&quot;</span>
        <span class="n">conn</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">connection</span>
        <span class="n">c</span> <span class="o">=</span> <span class="n">conn</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span>
        <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
            <span class="s2">&quot;UPDATE export_data SET digest = ? WHERE filepath_normalized = ?;&quot;</span><span class="p">,</span>
            <span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">_filepath_normalized</span><span class="p">),</span>
        <span class="p">)</span>
        <span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">_context_manager</span><span class="p">:</span>
            <span class="n">conn</span><span class="o">.</span><span class="n">commit</span><span class="p">()</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">exifdata</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;returns exifdata value for record&quot;&quot;&quot;</span>
        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_context_manager</span><span class="p">:</span>
            <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_exifdata</span><span class="p">()</span>
        <span class="k">with</span> <span class="bp">self</span><span class="o">.</span><span class="n">lock</span><span class="p">:</span>
            <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_exifdata</span><span class="p">()</span>

    <span class="nd">@exifdata</span><span class="o">.</span><span class="n">setter</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">exifdata</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">value</span><span class="p">:</span> <span class="nb">str</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;set exifdata value&quot;&quot;&quot;</span>
        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_context_manager</span><span class="p">:</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_exifdata_setter</span><span class="p">(</span><span class="n">value</span><span class="p">)</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="k">with</span> <span class="bp">self</span><span class="o">.</span><span class="n">lock</span><span class="p">:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_exifdata_setter</span><span class="p">(</span><span class="n">value</span><span class="p">)</span>

    <span class="k">def</span><span class="w"> </span><span class="nf">_exifdata</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;returns exifdata value for record&quot;&quot;&quot;</span>
        <span class="n">conn</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">connection</span>
        <span class="n">c</span> <span class="o">=</span> <span class="n">conn</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span>
        <span class="k">if</span> <span class="n">row</span> <span class="o">:=</span> <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
            <span class="s2">&quot;SELECT exifdata FROM export_data WHERE filepath_normalized = ?;&quot;</span><span class="p">,</span>
            <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_filepath_normalized</span><span class="p">,),</span>
        <span class="p">)</span><span class="o">.</span><span class="n">fetchone</span><span class="p">():</span>
            <span class="k">return</span> <span class="n">row</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>

        <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span>
            <span class="sa">f</span><span class="s2">&quot;No exifdata found in database for </span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">_filepath_normalized</span><span class="si">}</span><span class="s2">&quot;</span>
        <span class="p">)</span>

    <span class="k">def</span><span class="w"> </span><span class="nf">_exifdata_setter</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">value</span><span class="p">:</span> <span class="nb">str</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;set exifdata value&quot;&quot;&quot;</span>
        <span class="n">conn</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">connection</span>
        <span class="n">c</span> <span class="o">=</span> <span class="n">conn</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span>
        <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
            <span class="s2">&quot;UPDATE export_data SET exifdata = ? WHERE filepath_normalized = ?;&quot;</span><span class="p">,</span>
            <span class="p">(</span>
                <span class="n">value</span><span class="p">,</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_filepath_normalized</span><span class="p">,</span>
            <span class="p">),</span>
        <span class="p">)</span>
        <span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">_context_manager</span><span class="p">:</span>
            <span class="n">conn</span><span class="o">.</span><span class="n">commit</span><span class="p">()</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">src_sig</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">tuple</span><span class="p">[</span><span class="nb">int</span><span class="p">,</span> <span class="nb">int</span><span class="p">,</span> <span class="nb">int</span> <span class="o">|</span> <span class="kc">None</span><span class="p">]:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;return source file signature value&quot;&quot;&quot;</span>
        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_context_manager</span><span class="p">:</span>
            <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_src_sig</span><span class="p">()</span>
        <span class="k">with</span> <span class="bp">self</span><span class="o">.</span><span class="n">lock</span><span class="p">:</span>
            <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_src_sig</span><span class="p">()</span>

    <span class="nd">@src_sig</span><span class="o">.</span><span class="n">setter</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">src_sig</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">value</span><span class="p">:</span> <span class="nb">tuple</span><span class="p">[</span><span class="nb">int</span><span class="p">,</span> <span class="nb">int</span><span class="p">,</span> <span class="nb">int</span> <span class="o">|</span> <span class="kc">None</span><span class="p">]):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;set source file signature value&quot;&quot;&quot;</span>
        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_context_manager</span><span class="p">:</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_src_sig_setter</span><span class="p">(</span><span class="n">value</span><span class="p">)</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="k">with</span> <span class="bp">self</span><span class="o">.</span><span class="n">lock</span><span class="p">:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_src_sig_setter</span><span class="p">(</span><span class="n">value</span><span class="p">)</span>

    <span class="k">def</span><span class="w"> </span><span class="nf">_src_sig</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">tuple</span><span class="p">[</span><span class="nb">int</span><span class="p">,</span> <span class="nb">int</span><span class="p">,</span> <span class="nb">int</span> <span class="o">|</span> <span class="kc">None</span><span class="p">]:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;return source file signature value&quot;&quot;&quot;</span>
        <span class="n">conn</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">connection</span>
        <span class="n">c</span> <span class="o">=</span> <span class="n">conn</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span>
        <span class="k">if</span> <span class="n">row</span> <span class="o">:=</span> <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
            <span class="s2">&quot;SELECT src_mode, src_size, src_mtime FROM export_data WHERE filepath_normalized = ?;&quot;</span><span class="p">,</span>
            <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_filepath_normalized</span><span class="p">,),</span>
        <span class="p">)</span><span class="o">.</span><span class="n">fetchone</span><span class="p">():</span>
            <span class="n">mtime</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">row</span><span class="p">[</span><span class="mi">2</span><span class="p">])</span> <span class="k">if</span> <span class="n">row</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span> <span class="k">else</span> <span class="kc">None</span>
            <span class="k">return</span> <span class="p">(</span><span class="n">row</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">row</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">mtime</span><span class="p">)</span>

        <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span>
            <span class="sa">f</span><span class="s2">&quot;No src_sig found in database for </span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">_filepath_normalized</span><span class="si">}</span><span class="s2">&quot;</span>
        <span class="p">)</span>

    <span class="k">def</span><span class="w"> </span><span class="nf">_src_sig_setter</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">value</span><span class="p">:</span> <span class="nb">tuple</span><span class="p">[</span><span class="nb">int</span><span class="p">,</span> <span class="nb">int</span><span class="p">,</span> <span class="nb">int</span> <span class="o">|</span> <span class="kc">None</span><span class="p">]):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;set source file signature value&quot;&quot;&quot;</span>
        <span class="n">conn</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">connection</span>
        <span class="n">c</span> <span class="o">=</span> <span class="n">conn</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span>
        <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
            <span class="s2">&quot;UPDATE export_data SET src_mode = ?, src_size = ?, src_mtime = ? WHERE filepath_normalized = ?;&quot;</span><span class="p">,</span>
            <span class="p">(</span>
                <span class="n">value</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span>
                <span class="n">value</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span>
                <span class="n">value</span><span class="p">[</span><span class="mi">2</span><span class="p">],</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_filepath_normalized</span><span class="p">,</span>
            <span class="p">),</span>
        <span class="p">)</span>
        <span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">_context_manager</span><span class="p">:</span>
            <span class="n">conn</span><span class="o">.</span><span class="n">commit</span><span class="p">()</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">dest_sig</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">tuple</span><span class="p">[</span><span class="nb">int</span><span class="p">,</span> <span class="nb">int</span><span class="p">,</span> <span class="nb">int</span> <span class="o">|</span> <span class="kc">None</span><span class="p">]:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;return destination file signature&quot;&quot;&quot;</span>
        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_context_manager</span><span class="p">:</span>
            <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dest_sig</span><span class="p">()</span>
        <span class="k">with</span> <span class="bp">self</span><span class="o">.</span><span class="n">lock</span><span class="p">:</span>
            <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dest_sig</span><span class="p">()</span>

    <span class="nd">@dest_sig</span><span class="o">.</span><span class="n">setter</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">dest_sig</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">value</span><span class="p">:</span> <span class="nb">tuple</span><span class="p">[</span><span class="nb">int</span><span class="p">,</span> <span class="nb">int</span><span class="p">,</span> <span class="nb">int</span> <span class="o">|</span> <span class="kc">None</span><span class="p">]):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;set destination file signature&quot;&quot;&quot;</span>
        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_context_manager</span><span class="p">:</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dest_sig_setter</span><span class="p">(</span><span class="n">value</span><span class="p">)</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="k">with</span> <span class="bp">self</span><span class="o">.</span><span class="n">lock</span><span class="p">:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dest_sig_setter</span><span class="p">(</span><span class="n">value</span><span class="p">)</span>

    <span class="k">def</span><span class="w"> </span><span class="nf">_dest_sig</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">tuple</span><span class="p">[</span><span class="nb">int</span><span class="p">,</span> <span class="nb">int</span><span class="p">,</span> <span class="nb">int</span> <span class="o">|</span> <span class="kc">None</span><span class="p">]:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;return destination file signature&quot;&quot;&quot;</span>
        <span class="n">conn</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">connection</span>
        <span class="n">c</span> <span class="o">=</span> <span class="n">conn</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span>
        <span class="k">if</span> <span class="n">row</span> <span class="o">:=</span> <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
            <span class="s2">&quot;SELECT dest_mode, dest_size, dest_mtime FROM export_data WHERE filepath_normalized = ?;&quot;</span><span class="p">,</span>
            <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_filepath_normalized</span><span class="p">,),</span>
        <span class="p">)</span><span class="o">.</span><span class="n">fetchone</span><span class="p">():</span>
            <span class="n">mtime</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">row</span><span class="p">[</span><span class="mi">2</span><span class="p">])</span> <span class="k">if</span> <span class="n">row</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span> <span class="k">else</span> <span class="kc">None</span>
            <span class="k">return</span> <span class="p">(</span><span class="n">row</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">row</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">mtime</span><span class="p">)</span>

        <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span>
            <span class="sa">f</span><span class="s2">&quot;No dest_sig found in database for </span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">_filepath_normalized</span><span class="si">}</span><span class="s2">&quot;</span>
        <span class="p">)</span>

    <span class="k">def</span><span class="w"> </span><span class="nf">_dest_sig_setter</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">value</span><span class="p">:</span> <span class="nb">tuple</span><span class="p">[</span><span class="nb">int</span><span class="p">,</span> <span class="nb">int</span><span class="p">,</span> <span class="nb">int</span> <span class="o">|</span> <span class="kc">None</span><span class="p">]):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;set destination file signature&quot;&quot;&quot;</span>
        <span class="n">conn</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">connection</span>
        <span class="n">c</span> <span class="o">=</span> <span class="n">conn</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span>
        <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
            <span class="s2">&quot;UPDATE export_data SET dest_mode = ?, dest_size = ?, dest_mtime = ? WHERE filepath_normalized = ?;&quot;</span><span class="p">,</span>
            <span class="p">(</span>
                <span class="n">value</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span>
                <span class="n">value</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span>
                <span class="n">value</span><span class="p">[</span><span class="mi">2</span><span class="p">],</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_filepath_normalized</span><span class="p">,</span>
            <span class="p">),</span>
        <span class="p">)</span>
        <span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">_context_manager</span><span class="p">:</span>
            <span class="n">conn</span><span class="o">.</span><span class="n">commit</span><span class="p">()</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">photoinfo</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Returns info value&quot;&quot;&quot;</span>
        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_context_manager</span><span class="p">:</span>
            <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_photoinfo</span><span class="p">()</span>
        <span class="k">with</span> <span class="bp">self</span><span class="o">.</span><span class="n">lock</span><span class="p">:</span>
            <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_photoinfo</span><span class="p">()</span>

    <span class="nd">@photoinfo</span><span class="o">.</span><span class="n">setter</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">photoinfo</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">value</span><span class="p">:</span> <span class="nb">str</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Sets info value&quot;&quot;&quot;</span>
        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_context_manager</span><span class="p">:</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_photoinfo_setter</span><span class="p">(</span><span class="n">value</span><span class="p">)</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="k">with</span> <span class="bp">self</span><span class="o">.</span><span class="n">lock</span><span class="p">:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_photoinfo_setter</span><span class="p">(</span><span class="n">value</span><span class="p">)</span>

    <span class="k">def</span><span class="w"> </span><span class="nf">_photoinfo</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Returns info value&quot;&quot;&quot;</span>
        <span class="n">conn</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">connection</span>
        <span class="n">c</span> <span class="o">=</span> <span class="n">conn</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span>
        <span class="k">if</span> <span class="n">row</span> <span class="o">:=</span> <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
            <span class="s2">&quot;SELECT uuid FROM export_data WHERE filepath_normalized = ?;&quot;</span><span class="p">,</span>
            <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_filepath_normalized</span><span class="p">,),</span>
        <span class="p">)</span><span class="o">.</span><span class="n">fetchone</span><span class="p">():</span>
            <span class="n">uuid</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span>
                <span class="sa">f</span><span class="s2">&quot;No uuid found in database for </span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">_filepath_normalized</span><span class="si">}</span><span class="s2">&quot;</span>
            <span class="p">)</span>
        <span class="n">row</span> <span class="o">=</span> <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
            <span class="s2">&quot;SELECT photoinfo from photoinfo where uuid = ?;&quot;</span><span class="p">,</span>
            <span class="p">(</span><span class="n">uuid</span><span class="p">,),</span>
        <span class="p">)</span><span class="o">.</span><span class="n">fetchone</span><span class="p">()</span>
        <span class="k">return</span> <span class="n">row</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="k">if</span> <span class="n">row</span> <span class="k">else</span> <span class="kc">None</span>

    <span class="k">def</span><span class="w"> </span><span class="nf">_photoinfo_setter</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">value</span><span class="p">:</span> <span class="nb">str</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Sets info value&quot;&quot;&quot;</span>
        <span class="n">conn</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">connection</span>
        <span class="n">c</span> <span class="o">=</span> <span class="n">conn</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span>
        <span class="k">if</span> <span class="n">row</span> <span class="o">:=</span> <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
            <span class="s2">&quot;SELECT uuid FROM export_data WHERE filepath_normalized = ?;&quot;</span><span class="p">,</span>
            <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_filepath_normalized</span><span class="p">,),</span>
        <span class="p">)</span><span class="o">.</span><span class="n">fetchone</span><span class="p">():</span>
            <span class="n">uuid</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span>
                <span class="sa">f</span><span class="s2">&quot;No uuid found in database for </span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">_filepath_normalized</span><span class="si">}</span><span class="s2">&quot;</span>
            <span class="p">)</span>
        <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
            <span class="s2">&quot;INSERT OR REPLACE INTO photoinfo (uuid, photoinfo) VALUES (?, ?);&quot;</span><span class="p">,</span>
            <span class="p">(</span><span class="n">uuid</span><span class="p">,</span> <span class="n">value</span><span class="p">),</span>
        <span class="p">)</span>
        <span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">_context_manager</span><span class="p">:</span>
            <span class="n">conn</span><span class="o">.</span><span class="n">commit</span><span class="p">()</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">export_options</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Get export_options value&quot;&quot;&quot;</span>
        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_context_manager</span><span class="p">:</span>
            <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_export_options</span><span class="p">()</span>
        <span class="k">with</span> <span class="bp">self</span><span class="o">.</span><span class="n">lock</span><span class="p">:</span>
            <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_export_options</span><span class="p">()</span>

    <span class="nd">@export_options</span><span class="o">.</span><span class="n">setter</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">export_options</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">value</span><span class="p">:</span> <span class="nb">str</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Set export_options value&quot;&quot;&quot;</span>
        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_context_manager</span><span class="p">:</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_export_options_setter</span><span class="p">(</span><span class="n">value</span><span class="p">)</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="k">with</span> <span class="bp">self</span><span class="o">.</span><span class="n">lock</span><span class="p">:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_export_options_setter</span><span class="p">(</span><span class="n">value</span><span class="p">)</span>

    <span class="k">def</span><span class="w"> </span><span class="nf">_export_options</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Get export_options value&quot;&quot;&quot;</span>
        <span class="n">conn</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">connection</span>
        <span class="n">c</span> <span class="o">=</span> <span class="n">conn</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span>
        <span class="n">row</span> <span class="o">=</span> <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
            <span class="s2">&quot;SELECT export_options from export_data where filepath_normalized = ?;&quot;</span><span class="p">,</span>
            <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_filepath_normalized</span><span class="p">,),</span>
        <span class="p">)</span><span class="o">.</span><span class="n">fetchone</span><span class="p">()</span>
        <span class="k">return</span> <span class="n">row</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="k">if</span> <span class="n">row</span> <span class="k">else</span> <span class="kc">None</span>

    <span class="k">def</span><span class="w"> </span><span class="nf">_export_options_setter</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">value</span><span class="p">:</span> <span class="nb">str</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Set export_options value&quot;&quot;&quot;</span>
        <span class="n">conn</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">connection</span>
        <span class="n">c</span> <span class="o">=</span> <span class="n">conn</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span>
        <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
            <span class="s2">&quot;UPDATE export_data SET export_options = ? WHERE filepath_normalized = ?;&quot;</span><span class="p">,</span>
            <span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">_filepath_normalized</span><span class="p">),</span>
        <span class="p">)</span>
        <span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">_context_manager</span><span class="p">:</span>
            <span class="n">conn</span><span class="o">.</span><span class="n">commit</span><span class="p">()</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">timestamp</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;returns the timestamp value&quot;&quot;&quot;</span>
        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_context_manager</span><span class="p">:</span>
            <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_timestamp</span><span class="p">()</span>
        <span class="k">with</span> <span class="bp">self</span><span class="o">.</span><span class="n">lock</span><span class="p">:</span>
            <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_timestamp</span><span class="p">()</span>

    <span class="k">def</span><span class="w"> </span><span class="nf">_timestamp</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;returns the timestamp value&quot;&quot;&quot;</span>
        <span class="n">conn</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">connection</span>
        <span class="n">c</span> <span class="o">=</span> <span class="n">conn</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span>
        <span class="k">if</span> <span class="n">row</span> <span class="o">:=</span> <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
            <span class="s2">&quot;SELECT timestamp FROM export_data WHERE filepath_normalized = ?;&quot;</span><span class="p">,</span>
            <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_filepath_normalized</span><span class="p">,),</span>
        <span class="p">)</span><span class="o">.</span><span class="n">fetchone</span><span class="p">():</span>
            <span class="k">return</span> <span class="n">row</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>

        <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span>
            <span class="sa">f</span><span class="s2">&quot;No timestamp found in database for </span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">_filepath_normalized</span><span class="si">}</span><span class="s2">&quot;</span>
        <span class="p">)</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">error</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Any</span><span class="p">]</span> <span class="o">|</span> <span class="kc">None</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return error value&quot;&quot;&quot;</span>
        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_context_manager</span><span class="p">:</span>
            <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_error</span><span class="p">()</span>
        <span class="k">with</span> <span class="bp">self</span><span class="o">.</span><span class="n">lock</span><span class="p">:</span>
            <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_error</span><span class="p">()</span>

    <span class="nd">@error</span><span class="o">.</span><span class="n">setter</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">error</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">value</span><span class="p">:</span> <span class="nb">dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="nb">str</span><span class="p">]</span> <span class="o">|</span> <span class="kc">None</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Set error value&quot;&quot;&quot;</span>
        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_context_manager</span><span class="p">:</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_error_setter</span><span class="p">(</span><span class="n">value</span><span class="p">)</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="k">with</span> <span class="bp">self</span><span class="o">.</span><span class="n">lock</span><span class="p">:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_error_setter</span><span class="p">(</span><span class="n">value</span><span class="p">)</span>

    <span class="k">def</span><span class="w"> </span><span class="nf">_error</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Any</span><span class="p">]</span> <span class="o">|</span> <span class="kc">None</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return error value&quot;&quot;&quot;</span>
        <span class="n">conn</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">connection</span>
        <span class="n">c</span> <span class="o">=</span> <span class="n">conn</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span>
        <span class="k">if</span> <span class="n">row</span> <span class="o">:=</span> <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
            <span class="s2">&quot;SELECT error FROM export_data WHERE filepath_normalized = ?;&quot;</span><span class="p">,</span>
            <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_filepath_normalized</span><span class="p">,),</span>
        <span class="p">)</span><span class="o">.</span><span class="n">fetchone</span><span class="p">():</span>
            <span class="k">return</span> <span class="n">json</span><span class="o">.</span><span class="n">loads</span><span class="p">(</span><span class="n">row</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span> <span class="k">if</span> <span class="n">row</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="k">else</span> <span class="kc">None</span>

        <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;No error found in database for </span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">_filepath_normalized</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>

    <span class="k">def</span><span class="w"> </span><span class="nf">_error_setter</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">value</span><span class="p">:</span> <span class="nb">dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="nb">str</span><span class="p">]</span> <span class="o">|</span> <span class="kc">None</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Set error value&quot;&quot;&quot;</span>
        <span class="n">value</span> <span class="o">=</span> <span class="n">value</span> <span class="ow">or</span> <span class="kc">None</span>
        <span class="n">conn</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">connection</span>
        <span class="n">c</span> <span class="o">=</span> <span class="n">conn</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span>
        <span class="c1"># use default=str because some of the values are Path objects</span>
        <span class="n">error</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">dumps</span><span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="nb">str</span><span class="p">)</span> <span class="k">if</span> <span class="n">value</span> <span class="k">else</span> <span class="kc">None</span>
        <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
            <span class="s2">&quot;UPDATE export_data SET error = ? WHERE filepath_normalized = ?;&quot;</span><span class="p">,</span>
            <span class="p">(</span><span class="n">error</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">_filepath_normalized</span><span class="p">),</span>
        <span class="p">)</span>
        <span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">_context_manager</span><span class="p">:</span>
            <span class="n">conn</span><span class="o">.</span><span class="n">commit</span><span class="p">()</span>

    <span class="k">def</span><span class="w"> </span><span class="nf">asdict</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Any</span><span class="p">]:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return dict of self&quot;&quot;&quot;</span>
        <span class="n">exifdata</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">loads</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">exifdata</span><span class="p">)</span> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">exifdata</span> <span class="k">else</span> <span class="kc">None</span>
        <span class="n">photoinfo</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">loads</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">photoinfo</span><span class="p">)</span> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">photoinfo</span> <span class="k">else</span> <span class="kc">None</span>
        <span class="k">return</span> <span class="p">{</span>
            <span class="s2">&quot;filepath&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">filepath</span><span class="p">,</span>
            <span class="s2">&quot;filepath_normalized&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">filepath_normalized</span><span class="p">,</span>
            <span class="s2">&quot;uuid&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">uuid</span><span class="p">,</span>
            <span class="s2">&quot;timestamp&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">timestamp</span><span class="p">,</span>
            <span class="s2">&quot;digest&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">digest</span><span class="p">,</span>
            <span class="s2">&quot;src_sig&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">src_sig</span><span class="p">,</span>
            <span class="s2">&quot;dest_sig&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">dest_sig</span><span class="p">,</span>
            <span class="s2">&quot;export_options&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">export_options</span><span class="p">,</span>
            <span class="s2">&quot;exifdata&quot;</span><span class="p">:</span> <span class="n">exifdata</span><span class="p">,</span>
            <span class="s2">&quot;error&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">error</span><span class="p">,</span>
            <span class="s2">&quot;photoinfo&quot;</span><span class="p">:</span> <span class="n">photoinfo</span><span class="p">,</span>
        <span class="p">}</span>

    <span class="k">def</span><span class="w"> </span><span class="nf">json</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">indent</span><span class="o">=</span><span class="kc">None</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return json string of self&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="n">json</span><span class="o">.</span><span class="n">dumps</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">asdict</span><span class="p">(),</span> <span class="n">indent</span><span class="o">=</span><span class="n">indent</span><span class="p">)</span>

    <span class="k">def</span><span class="w"> </span><span class="fm">__enter__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_context_manager</span> <span class="o">=</span> <span class="kc">True</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">lock</span><span class="o">.</span><span class="n">acquire</span><span class="p">()</span>
        <span class="k">return</span> <span class="bp">self</span>

    <span class="k">def</span><span class="w"> </span><span class="fm">__exit__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">exc_type</span><span class="p">,</span> <span class="n">exc_value</span><span class="p">,</span> <span class="n">traceback</span><span class="p">):</span>
        <span class="k">if</span> <span class="n">exc_type</span> <span class="ow">and</span> <span class="bp">self</span><span class="o">.</span><span class="n">_conn</span><span class="o">.</span><span class="n">in_transaction</span><span class="p">:</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_conn</span><span class="o">.</span><span class="n">rollback</span><span class="p">()</span>
        <span class="k">elif</span> <span class="bp">self</span><span class="o">.</span><span class="n">_conn</span><span class="o">.</span><span class="n">in_transaction</span><span class="p">:</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_conn</span><span class="o">.</span><span class="n">commit</span><span class="p">()</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_context_manager</span> <span class="o">=</span> <span class="kc">False</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">lock</span><span class="o">.</span><span class="n">release</span><span class="p">()</span>
</pre></div>
        </article>
      </div>
      <footer>
        
        <div class="related-pages">
          
          
        </div>
        <div class="bottom-of-page">
          <div class="left-details">
            <div class="copyright">
                Copyright &#169; 2021, Rhet Turnbull
            </div>
            Made with <a href="https://www.sphinx-doc.org/">Sphinx</a> and <a class="muted-link" href="https://pradyunsg.me">@pradyunsg</a>'s
            
            <a href="https://github.com/pradyunsg/furo">Furo</a>
            
          </div>
          <div class="right-details">
            
          </div>
        </div>
        
      </footer>
    </div>
    <aside class="toc-drawer no-toc">
      
      
      
    </aside>
  </div>
</div><script src="../../_static/documentation_options.js?v=63568c49"></script>
    <script src="../../_static/doctools.js?v=9bcbadda"></script>
    <script src="../../_static/sphinx_highlight.js?v=dc90522c"></script>
    <script src="../../_static/scripts/furo.js?v=46bd48cc"></script>
    <script src="../../_static/clipboard.min.js?v=a7894cd8"></script>
    <script src="../../_static/copybutton.js?v=f281be69"></script>
    </body>
</html>